2013-06-02 45 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(); 

    } 

時鎖定,在外部互斥 預期這正常工作。

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

由於在第一生產國,可以同步this,這是Runnable,而不是生產者本身。

因此,您需要使用synchronized(producer)來代替,除非它不會編譯,因爲producer尚未在該行上提供。

或者你能說出你的Runnable:

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

,並在您的消費:

synchronized(producerRunnable) {...} 

但是你有一個單獨的互斥第二種方法是優選的,除了在""即鎖定是一個極壞的因爲這是一個全局常量(空字符串在字符串池中)。你應該更喜歡這樣的東西,而不是:

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

是的,互斥量應該是Object()。購買我沒有得到如何同步生產者線程。如何移出producerRunnable會導致同步。在生產線上發生? – tintin

+0

你的第一個生產者中的'synchronized(this)'在Runnable上同步,而不是在Thread上。而在你的消費者中,當你調用'synchronized(producer)'時,你在線程上同步而不是在Runnable上運行。所以你正在使用兩個不同的鎖。由於生產者Thread中的Runnable實例沒有名稱(匿名),因此除非您給它起一個名字(我的第一個提議),否則您無法將其用作鎖。 – assylias

+0

感謝您的澄清:-) – tintin

0

在supportig assylias的答案在這裏是另一種選擇。

private Object lock = new Object(); 

鎖定

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

解鎖

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

等待當兩個線程都使用相同的對象/類鎖定通知的作品。在你的情況下,用於等待/通知的鎖是不同的,如下所述:

synchronized(producer) // lock on producer object 

synchronized(this) // Runnable object.