2013-10-02 1 views
0

나는 확실히 동시성 지옥에있어. 나는 내가하려고하는 것에 대한 좋은/효율적인 해결책을 찾을 수 없다. 텍스트 파일을 읽는 Producer 스레드를 공유 BlockedQueue 정보를 넣습니다. 그리고 공유 된 BlockedQueue를 사용하여 데이터를 읽는 소비자가 있으며 데이터로 무거운 것을 처리합니다. 나는 GUI가 세 버튼 : 시작, 일시 중지중지입니다.생산자/소비자 관계를 시작, 일시 중지 및 중단하는 방법은 무엇입니까?

생산자와 소비자 나 생산자가 파일을 열고 자하는 시작 옵션을

(예를 들어, 통계 또는 일부 개체를 반환) Runnable를 구현하고 각각의 계산에 대한 정보에 액세스하는 방법을 제공 모두 BlockedQueue에 데이터를 넣기 시작합니다. 또한 소비자는 데이터를 가져 와서 계산을 시작합니다.

일시 중지 옵션 Producer가 BlockedQueue에 데이터를 저장하지 못하도록하고 싶지만 동시에 프로듀서의 인스턴스 변수에 액세스 할 수 있기를 원합니다. Consumer에 대해서도 마찬가지입니다. 무거운 것을 중단하고 싶지만 Consumer에서 정의 된 인스턴스 변수와 메소드에 액세스 할 수 있습니다.

옵션을 사용하면 생산자와 소비자가 다시 설정되도록 할 수 있습니다. 즉, 깨끗한 상태에서 시작하는 것처럼 말입니다.

제 질문은 이것을 효율적으로 구현하는 방법입니다. 특히 일시 중지를 확인 하시겠습니까?

이 psudo-code와 같은 것이 효율적입니까?

Enum state; 

class Producer implements Runnable { 
    public List someList;//accessed from the event-dispatching thread 
    public void Run() { 
     synchronized(state) { 
      if(state == Enum.paused) { 
       //do nothing 
      } 
      else if(state == Enum.running) { 
       //put stuff into BlockedQueue 
      } 
      else if (state == Enum.stopped) { 
       // reopen file and set state = running 
      } 


     } 
    } 
} 

class Consumer implements Runnable { 
    public Map someMap;//accessed from the event-dispatching thread 
    public void Run() { 
     synchronized(state) { 
      if(state == Enum.paused) { 
       //do nothing 
      } 
      else if(state == Enum.running) { 
       //start consuming from the BlockedQueue and do heavy computation 
      } 
      else if (state == Enum.stopped) { 
       // clear stuff to start clean and set state = running 
      } 


     } 
    } 
} 
+0

Sidenote : 열거 형을 일관되게 유지하십시오. 현재 상태 ('isPause')를 묘사하는 객체, 현재 동작을 묘사하는 객체 ('running'), 동작을 기술하는 객체 ('stop')가 있습니다. –

+2

'독약 '을 들여다보십시오. –

+0

이 질문은 Brian Goetz 등 7 장의 마케팅 캠페인처럼 들립니다. Java Concurrency in Practice. 이 장에서는 취소 가능성과 인터럽트 가능성을 다루며 "프로그램이 취소 및 종료를 처리하는 방법은 진정으로 강력한 동시 응용 프로그램을 단순히 작동하는 프로그램과 분리하는 요소 중 하나입니다"라고 설명합니다. Joshua Bloch의 Effective Java, 2nd Ed.보다 진보 된 읽기이지만, Java에서 심각한 동시 프로그래밍을하고자하는 사람들을 위해 반드시 읽어야합니다 (독극물을 다룹니다). – scottb

답변

1

제 질문은 이것을 효율적으로 구현하는 방법입니다. 특히 일시 중지를 확인 하시겠습니까? 이 psudo-code와 같은 것이 효율적일까요?

필드를 사용하여 ConsumerProducer이 작업을 수행하는 것이 좋습니다. 열거 형에 대한 모든 업데이트가 스레드간에 올바르게 동기화되도록 필드가 volatile인지 확인해야합니다. 또는 synchronized 키워드를 사용하는 경우 업데이트 될 때 synchronized이 필요합니다. 이 경우에는 차단할 이유가 없으므로 volatile이 좋습니다.

public class Consumer { 
    private volatile Enum state; 
    ... 
    if(state == Enum.paused) { 

사람들은 해결책으로 "독약"을 언급했습니다. 상태를 변경하는 객체를 큐에 넣을 때입니다. 이 솔루션의 문제점은 소비자가 객체에서 작업중인 경우 대기열을 검사하지 않기 때문에 작동하지 않는다는 것입니다. 큐에 수 있지만 state 필드 잘 작동합니다 같아요.

생산자와 소비자 모두 Runnable을 구현하고 각각의 계산에 대한 정보에 액세스하는 메소드를 제공합니다 (예 :.일부 통계 또는 일부 객체 반환)

ProducerConsumer 개체는 여전히 존재하며 액세스 할 수 있습니다. 모든 경우에 스레드간에 공유되는 필드에 대한 모든 업데이트가 올바르게 동기화되어야하는지 확인해야합니다.

제 질문은 이것을 효율적으로 구현하는 방법입니다. 특히 일시 중지를 확인 하시겠습니까?

효율성 측면에서 필드 액세스는 일반적인 필드 액세스보다 약 100 배 느린 것으로 보입니다. 각 줄마다 상태 검사를하지는 않겠지 만 각 처리 루프의 맨 위에서 확인하거나 if (loopCounter % 1000 == 0)과 같은 작업을하면 루프를 통해 모든 X 시간을 일시 중지했는지 확인할 수 있습니다. 성능이 저하되는 경우 많이 볼 수 없습니다.

+1

여기서 핵심은 InterruptedException 관용구를 마스터하는 것입니다. – scottb

+0

@ 그레이 여기 내 질문을 확인해 주시겠습니까? http://stackoverflow.com/questions/19177770/how-to-make-two-threads-wait-then-run-given-that-use-a-blockedqueue –

0

데이터 또는 제어 메시지인지 여부에 관계없이 대기열에 들어가는 메시지에 태그를 지정할 수 있습니다. 모든 쓰레드는 오직 하나의 입력 (메시지) 큐를 가진다.

관련 문제