2017-02-15 5 views
0

Ich versuche, einzelne Verbraucher/Produzent Problem mit Monitor in Java zu lösen, und der Code ist wie folgt. Wenn ich diesen Code ausführe, wird er endlich stecken bleiben. Der typischste Fall ist, dass der Verbraucher wait() anruft und der Produzent dann weiter produziert, aber den Verbraucher nicht benachrichtigen kann (obwohl er notify() anrufen wird). Ich weiß nicht, warum es passiert. Java-Code:Monitor in meinem Java-Programm in einen Deadlock

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

Angenommen, zwei Verbraucher kommen zuerst, beide geben 'wait()' ein. Dann kommt ein Producer, der einen 'notify()' ausgibt. Unmittelbar danach, bevor ein Verbraucher geweckt wird, kommt ein anderer Produzent, fügt einen Artikel hinzu, aber ohne Benachrichtigungen. Jetzt wird nur ein Verbraucher geweckt. – ZhongYu

+0

@ZhongYu Danke für Ihren Kommentar. Ich erstelle nur einen Produzenten und einen Verbraucher in der Hauptfunktion, und das Programm kann noch nicht normal laufen. Warum das? Beachten Sie, dass ich erwähnt habe, dass das Programm auf ein Problem mit einzelnen Produzenten/Verbrauchern abzielt. –

+0

Sie sollten 'new Monitor()' nicht erneut aufgerufen haben - verwenden Sie einfach den in main() erstellten Monitor – ZhongYu

Antwort

1

Wenn die Steuerung jeder Thread die produce() oder consume() Methoden eintritt, die Größe und Länge beide Null sind und somit beide Threads warten auf die andere zu benachrichtigen. Brechen Sie das und Ihr Code wird aus dem Stillstand kommen.

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(); 
    } 

Dies geschieht, weil Sie einen Standardkonstruktor haben, die Sie in der run() Methode Ihrer Producer und Consumer-Objekte aufrufen.

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 

hoffe, das hilft!

+0

Aber ich initialisiere monitor.length auf 10 ('Monitormonitor = neuer Monitor (10)'), also sollte die Länge nicht 0 sondern 10 sein. Habe ich mich geirrt? –

+0

Ich habe die Größe und Länge vor dem Beginn der 'while' Anweisung ausgedruckt. Ich habe Größe = 0 und Länge = 0. – anacron

+0

Siehe meine aktualisierte Antwort .. – anacron