2013-06-02 3 views
0

저는 하나의 엔트리 만 가지고있는 int itemHolder에 대한 소비자 생산자 문제를 시도하고 있습니다. 나는 소비자 스레드가 항목을 넣었을 때 소비자 스레드가 제작자 스레드에 알리지 않는 이유를 모른다. 예상되는 동작은 제작자가 항목을 itemHolder에 넣을 때까지 소비자 스레드가 대기한다는 것이다. 반면에 외부 mutax 객체에서 잠금을 사용할 때 완벽하게 작동합니다. 외부 뮤텍스 예상대로이 제대로 작동 에 잠금으로여기 왜 대기/알림이 발생하지 않습니까?

public class ProducerConsumer { 

    public static void main(String... args) { 
     new ProducerConsumer().execute(); 
    } 

    private volatile int itemHolder = -1; // -1 value represent that ItemHolder is empty 

    private void execute() { 
     final Thread producer = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       for (int i = 1; i < 5; i++) { 
        synchronized (this){ 
         while (itemHolder != -1){ // ItemHolder is full 
          try { 
           this.wait(); 
          } catch (InterruptedException e) { 
           e.printStackTrace(); 
          } 
         } 
         itemHolder = i; 
         notify(); 
         System.out.println(String.format("producer: ItemHolder has value, Consumer notified...")); 

        } 
       } 

      } 


     }, "Producer-thread"); 

     final Thread consumer = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       while (true){ 
        synchronized (producer){ 
         try { 
          while (itemHolder == -1){ // Don't consume if itemHolder don't have a value 
           producer.wait(); 
          } 
          System.out.println(String.format("CONSUMER: consuming %s...", itemHolder)); 
          itemHolder = -1; // re-initialize the itemHolder 
          producer.notify(); 
         } catch (InterruptedException e) { 
          e.printStackTrace(); 
         } 

        } 
       } 
      } 
     }, "Consumer-thread"); 

     consumer.start(); 
     producer.start(); 

    } 

. 첫 번째 프로듀서, 당신은 Runnable 아니라 생산 자체 인 this에 동기화하기 때문에

public class ProducerConsumerWithMutex { 

    public static void main(String... args) { 
     new ProducerConsumerWithMutex().execute(); 
    } 
    private final String mutex = ""; 
    private volatile int itemHolder = -1; 

    private void execute() { 
     final Thread producer = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       for (int i = 1; i < 5; i++) { 
        synchronized (mutex){ 
         while (itemHolder != -1){ // itemHolder is full 
          try { 
           mutex.wait(); 
          } catch (InterruptedException e) { 
           e.printStackTrace(); 
          } 
         } 
         itemHolder = i; 
         System.out.println(String.format("producer: producing %s...", i)); 
         mutex.notify(); 
         System.out.println(String.format("producer: Consumer notified, itemHolder has item...")); 

        } 
       } 

      } 


     }, "Producer-thread"); 

     final Thread consumer = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       while (true){ 
        synchronized (mutex){ 
         try { 
          while (itemHolder == -1){ 
           System.out.println("CONSUMER: itemHolder is empty, waiting..."); 
           mutex.wait(); 
          } 
          System.out.println(String.format("CONSUMER: consuming %s...", itemHolder)); 
          itemHolder = -1; 
          mutex.notify(); 
         } catch (InterruptedException e) { 
          e.printStackTrace(); 
         } 

        } 
       } 
      } 
     }, "Consumer-thread"); 

     consumer.start(); 
     producer.start(); 

    } 

답변

4

.

따라서 synchronized(producer)을 사용해야합니다. 단, 해당 라인에서는 producer을 사용할 수 없으므로 컴파일되지 않습니다.

또는 당신의 이름을 수있는 당신의 Runnable :

Runnable producerRunnable = ...; //synchronized on this 

하고 소비자의

:

synchronized(producerRunnable) {...} 

그러나 별도의 뮤텍스와 두 번째 접근 방식은 ""에 그 잠금을 제외하고, 바람직 것은 매우 나쁜 idea는 전역 상수이므로 빈 문자열은 문자열 풀에 있습니다. 대신 다음과 같은 것을 선호해야합니다.

private final Object mutex = new Object(); 
+0

예, 뮤텍스는 Object()이어야합니다. buy 제작자 스레드를 동기화하는 방법을 알지 못했습니다. producerRunnable을 이동하면 동기화가 어떻게 발생합니까? 일어날 생산자 스레드에서? – tintin

+0

첫 프로듀서의'synchronized (this)'는 스레드가 아닌 Runnable과 동기화됩니다. 그리고 소비자의 경우,'synchronized (producer)'를 호출하면 Runnable이 아닌 Thread에서 동기화됩니다. 그래서 두 개의 다른 자물쇠를 사용하고 있습니다. 그리고 제작자 Thread의 Runnable 인스턴스에는 이름이 없으므로 (익명 임) 이름을 지정하지 않으면 잠금으로 사용할 수 없습니다 (첫 번째 제안). – assylias

+0

설명해 주셔서 감사합니다 :-) – tintin

0

답변을 얻은 후에는 여기 '또 다른 옵션이 있습니다.

private Object lock = new Object(); 

synchronized (lock){ 
     lock.wait(); 
} 

synchronized (lock){ 
     lock.notify(); 
} 
1

는 스레드가 같은 객체/클래스 잠금을 사용하는 경우 작업을 통지 대기 잠금을 해제 잠급니다. 귀하의 경우 대기/알림에 사용 된 잠금은 여기에 언급 된 것과 다릅니다.

synchronized(producer) // lock on producer object 

synchronized(this) // Runnable object. 
관련 문제