2017-02-15 23 views
0

我試圖解決使用Java中的監視器的單個消費者/生產者問題,代碼如下。當我運行這段代碼時,它最終會陷入困境。最典型的情況是消費者撥打wait(),然後生產者繼續生產,但不能通知消費者(儘管它會呼叫notify())。我不知道爲什麼會發生。 Java代碼:監視器在我的Java程序進入死鎖

import java.util.*; 
class Monitor { 
    int length; 
    int size; 
    int begin, end; 
    int queue[]; 
    private static Random randGenerator; 
    public Monitor() {} 
    public Monitor(int length) { 
     this.length = length; 
     this.size = 0; 
     begin = end = 0; 
     queue = new int[length]; 
     randGenerator = new Random(10); 
    } 
    public synchronized void produce() throws InterruptedException { 
     while(size == length) { 
      System.out.println("Producer waiting"); 
      wait(); 
     } 
     int produced = randGenerator.nextInt(); 
     size++; 
     queue[end] = produced; 
     end = (end + 1) % length; 
     System.out.println("Produce element " + produced + " size "+size); 
     // When size is not 1, no thread is blocked and therefore don't need to notify 
     if(size == 1) { 
      System.out.println("Notify consumer"); 
      notify(); 
     } 
    } 
    public synchronized void consume() throws InterruptedException { 
     while(size == 0) { 
      System.out.println("Consumer waiting, size " + size); 
      wait(); 
     } 
     size--; 
     System.out.println("Consume element " + queue[begin] + " size " + size); 
     begin = (begin + 1) % length; 
     if(size == length - 1) { 
      System.out.println("Notify producer"); 
      notify(); 
     } 
    } 
} 

class Producer implements Runnable { 
    Monitor producer; 
    public Producer(Monitor m) { 
     producer = m; 
    } 
    @Override 
    public void run() { 
     producer = new Monitor(); 
     System.out.println("Producer created"); 
     try { 
      while(true) { 
       producer.produce(); 
      } 
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
class Consumer implements Runnable { 
    Monitor consumer; 
    public Consumer(Monitor m) { 
     consumer = m; 
    } 
    @Override 
    public void run() { 
     System.out.println("Consumer created"); 
     consumer = new Monitor(); 
     try { 
      while(true) { 
       consumer.consume(); 
      } 
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

public class monitorTest { 
    public static void main(String args[]) { 
     Monitor monitor = new Monitor(10); 
     Thread t1 = new Thread(new Producer(monitor)); 
     Thread t2 = new Thread(new Consumer(monitor)); 
     t1.start(); 
     t2.start(); 
    } 
} 
+0

假設有2位消費者先到,都進入'wait()'。然後生產者來了,發出一個'notify()'。緊接着,在任何消費者被喚醒之前,另一個生產者來了,添加了一個項目,但沒有任何通知。現在,只有一個消費者會被喚醒。 – ZhongYu

+0

@中裕感謝您的評論。我在主函數中只創建一個生產者和一個消費者,程序仍然無法正常運行。這是爲什麼?請注意,我已經提到該計劃針對單一生產者/消費者問題。 –

+0

你不應該再次調用'new Monitor()' - 只需使用在main()中創建的監視器() – ZhongYu

回答

1

當每個線程的控制進入produce()consume()方法中,尺寸和長度均爲零,因此這兩個線程正在等待其它通知。打破這一點,你的代碼將從僵局中走出來。

public synchronized void produce() throws InterruptedException { 
    while(size == length) { // size is 0 and length is 0; so wait 
     System.out.println("Producer waiting"); 
     wait(); 
    } 

public synchronized void consume() throws InterruptedException { 
    while(size == 0) { // size is 0 so wait 
     System.out.println("Consumer waiting, size " + size); 
     wait(); 
    } 

發生這種情況,因爲你有你的生產者和消費者對象的run()方法中調用默認的構造函數。

class Producer implements Runnable { 
    Monitor producer; 
    public Producer(Monitor m) { 
     producer = m; 
    } 
    @Override 
    public void run() { 
     producer = new Monitor(); // REMOVE THIS 

class Consumer implements Runnable { 
    Monitor consumer; 
    public Consumer(Monitor m) { 
     consumer = m; 
    } 
    @Override 
    public void run() { 
     System.out.println("Consumer created"); 
     consumer = new Monitor(); // AND REMOVE THIS 

希望這有助於!

+0

但我把monitor.length初始化爲10('Monitor monitor = new Monitor(10)'),所以長度不應該是0,而是10.我錯了嗎? –

+0

我在'while'語句開始之前打印了大小和長度。我得到大小= 0和長度= 0. – anacron

+0

看到我更新的答案.. – anacron