2016-07-24 74 views
4

我有一個ConsumerProducer對象,我想從兩個不同的線程獲取鎖。類是如下:wait()/ notify()無法正常工作

public class ConsumerProducer { 

    public String stringPool = null; 

    public void put(String s){ 
     stringPool = s; 
    } 

    public String get(){ 
     String ret = stringPool; 
     stringPool = null; 
     return ret; 
    } 

} 

線程實現類是如下:

public class WaitNotifyTest implements Runnable { 

    private String threadType; 
    public ConsumerProducer cp; 
    public static volatile int i = 1; 

    public WaitNotifyTest(String threadType, ConsumerProducer cp) { 
     this.threadType = threadType; 
     this.cp = cp; 
    } 

    public static void main(String[] args) throws InterruptedException { 

     ConsumerProducer cp = new ConsumerProducer(); 
     WaitNotifyTest test1 = new WaitNotifyTest("Consumer", cp); 
     WaitNotifyTest test2 = new WaitNotifyTest("Producer", cp); 

     Thread t1 = new Thread(test1); 
     Thread t2 = new Thread(test2); 

     t1.start(); 
     t2.start(); 
     t1.join(); 
     t2.join(); 
    } 

    @Override 
    public void run() { 
     while (true) { 

      if (threadType.equalsIgnoreCase("Consumer")) { 
       synchronized (cp) { 
        try { 
         if (null != cp.get()) { 
          cp.wait(); 
         } 
         consume(); 
         System.out.println("notify from Consumer"); 
         cp.notify(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 

      } else { 
       synchronized (cp) { 
        try { 
         if (null == cp.get()) { 
          cp.wait(); 
         } 
         produce(); 
         System.out.println("notify from Producer"); 
         cp.notify(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
      if (i == 5) { 
       break; 
      } 
      i++; 
     } 
    } 

    public void consume() { 
     System.out.println("Putting: Counter" + i); 
     cp.put("Counter" + i); 
    } 

    public void produce() { 
     System.out.println("getting: " + cp.get()); 
    } 

} 

但是當我運行它正面臨某種僵局的代碼,它是像

卡印刷
Putting: Counter3 
notify from Consumer 

有些事情發生了嚴重的錯誤,但我無法識別。請幫忙。

+0

我通常會盡量避免等待/通知,因爲它們比CountDownLatch和CyclicBarrier更難以推理。 –

回答

1

你的消費者正在做生產者的工作,生產者正在做消費者的工作。 交換自己的責任,並修改條件等待。請參閱下面的代碼。

  1. 消費者會在沒有東西可以得到時等待,他會釋放cp的鎖。這樣生產者有機會進入同步塊。
  2. 製片人只有在沒有任何東西或他會等待時纔會產生。之後,他將釋放cp的鎖定。這樣消費者有機會進入同步塊。
  3. 消費者是誰讓事情離開。
  4. 製片人是誰把東西放在桌子上。
  5. 根據您的評論。你想把計數器從1到5,所以你應該只在Producer線程中添加i ++。你如何控制它在兩個線程中的增長?
  6. 您不會判斷消費者或生產者是否從cp對象調用get()對象,但將null分配給stringPool。這顯然是錯誤的,並會使消費者從公共空間中消失。我添加了一個新方法clearString(),只有當消費者使用產品時,它纔會將公共空間設置爲null。

    public class WaitNotifyTest implements Runnable { 
    
    private String threadType; 
    public ConsumerProducer cp; 
    public static volatile int i = 0; 
    
    public WaitNotifyTest(String threadType, ConsumerProducer cp) { 
        this.threadType = threadType; 
        this.cp = cp; 
    } 
    
    public static void main(String[] args) throws InterruptedException { 
    
        ConsumerProducer cp = new ConsumerProducer(); 
        WaitNotifyTest test1 = new WaitNotifyTest("Consumer", cp); 
        WaitNotifyTest test2 = new WaitNotifyTest("Producer", cp); 
    
        Thread t1 = new Thread(test1); 
        Thread t2 = new Thread(test2); 
    
        t1.start(); 
        t2.start(); 
        t1.join(); 
        t2.join(); 
    } 
    
    @Override 
    public void run() { 
        while (true) { 
         if (threadType.equalsIgnoreCase("Consumer")) { 
          synchronized (cp) { 
           try { 
            /* 
            * Consumer will wait when there is nothing to get and he will release the lock of cp. 
            * So that producer has change to go into the synchronized block. 
            */ 
    
            if (null == cp.get()) { 
             cp.wait(); 
            } 
            consume(); 
            System.out.println("notify from Consumer"); 
            cp.notify(); 
           } catch (InterruptedException e) { 
            e.printStackTrace(); 
           } 
          } 
    
         } else { 
          synchronized (cp) { 
           try { 
            /* 
            * Producer only produce when there is nothing or he will wait. At the same time, he will release the lock of cp. 
            * So that consumer has chance to go into the synchronized block. 
            */ 
            if (null != cp.get()) { 
             cp.wait(); 
            } 
            i++; 
            produce(); 
            System.out.println("notify from Producer"); 
            cp.notify(); 
           } catch (InterruptedException e) { 
            e.printStackTrace(); 
           } 
          } 
         } 
         if (i == 5) { 
          break; 
         } 
    
        } 
    } 
    
    public void consume() { 
        System.out.println("getting: " + cp.get()); 
        cp.clearString(); 
    } 
    
    public void produce() { 
        System.out.println("Putting: Counter" + i); 
        cp.put("Counter" + i); 
    }} 
    

另見ConsumerProducer類。

public class ConsumerProducer { 
     public String stringPool = null; 

     public void put(String s){ 
      stringPool = s; 
     } 

     public String get(){ 
      return stringPool; 
     } 

     public void clearString(){ 
      stringPool = null; 
     } 
} 
+0

謝謝@Gearon。僵局消失了。然而,產量並不如預期。 輸出: '把:C1的 生產 通知獲得:空 從消費者 通知推杆:C3的 生產 通知獲得:C3的 從消費者 通知推杆:Counter5 通知生產 獲得:Counter5 通知來自消費者' 雖然不一致。 –

+0

預期輸出: '把:C1的 生產 通知獲得:C1的 從消費者 通知推杆:C2的 生產 通知獲得:C2的 從消費者 通知推杆:C3的 生產 通知獲得:C3的 從消費者 通知推杆:Counter4 生產 得到通知:Counter4 從消費者 通知推杆:Counter5 通知生產 獲得:計數器5 消費者通知# –

+0

@AnirbanB。請檢查我的更新。謝謝。 – Gearon

0

更新的代碼是在這裏: ConsumerProducer.java:
公共類ConsumerProducer {

public volatile String stringPool = null; 

    public void put(String s){ 
     this.stringPool = s; 
    } 

    public String get(){ 
     String ret = this.stringPool; 
     //this.stringPool = null; 
     return ret; 
    } 
    //added 
    public void clearString(){ 
     this.stringPool = null; 
    } 

} 

WaitNotifyTest.java 公共類WaitNotifyTest實現Runnable {

private String threadType; 
    public ConsumerProducer cp; 
    public static volatile int i = 0; 

    public WaitNotifyTest(String threadType, ConsumerProducer cp) { 
     this.threadType = threadType; 
     this.cp = cp; 
    } 

    public static void main(String[] args) throws InterruptedException { 

     ConsumerProducer cp = new ConsumerProducer(); 
     WaitNotifyTest test1 = new WaitNotifyTest("Consumer", cp); 
     WaitNotifyTest test2 = new WaitNotifyTest("Producer", cp); 

     Thread t1 = new Thread(test1); 
     Thread t2 = new Thread(test2); 

     t1.start(); 
     t2.start(); 
     t1.join(); 
     t2.join(); 
    } 

    @Override 
    public void run() { 
     while (true) { 

      if (threadType.equalsIgnoreCase("Consumer")) { 
       synchronized (cp) { 
        try { 
         if (null == cp.get()) { 
          cp.wait(); 
         } 
         consume(); 
         System.out.println("notify from Consumer"); 
         cp.notify(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 

      } else { 
       synchronized (cp) { 
        try { 
         if (null != cp.get()) { 
          cp.wait(); 
         } 
         i++; 
         produce(); 
         System.out.println("notify from Producer"); 
         cp.notify(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
      if (i == 5) { 
       break; 
      } 

     } 
    } 

    public void produce() { 
     System.out.println("Putting: Counter" + i); 
     cp.put("Counter" + i); 
    } 

    public void consume() { 
     System.out.println("getting: " + cp.get()); 
     cp.clearString(); 
    } 

}