2017-07-20 3 views
-1

Ich habe zwei Klassen Threads und . In Thread habe ich zwei Threads ausgeführt: eine, um ein Element hinzuzufügen, und eine zweite, um das Element zu entfernen, das hinzugefügt wurde.Benachrichtigen Methode nicht weckt die Warte-Methode in Schleife

Das Problem ist, dass in consume() nach dem Entfernen des ersten Elements die Benachrichtigungs nicht die Warte-Methode aufwachen wird. In der zweiten Iteration wird dies gemeldet.

Meine Anforderung ist, ich möchte den Hersteller für jede Iteration benachrichtigen. Was muss ich tun?

public class Threads { 
    public static void main(String args[]){ 
     ProducerConsumer pc = new ProducerConsumer(); 
     new Thread(){ 
     public void run(){pc.produce();} 
     }.start(); 

     new Thread(){ 
     public void run(){pc.consume();} 
     }.start(); 
    } 
} 


import java.util.ArrayList; 
    import java.util.Collections; 
    import java.util.LinkedList; 
    import java.util.List; 

    public class ProducerConsumer { 
     LinkedList<Integer> list = new LinkedList<>(); 
     public synchronized void produce() { 
      for(int j = 0; j < 5; j++) { 
       list.add(j); 
       System.out.println(list+"producer"); 
       System.out.println("producing and adding values"+j); 
        try { 
         wait(); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
      } 

     } 
     public synchronized void consume() { 
       for(int j = 0; j < 5; j++) { 
        System.out.println(list+"list"+"consumer"); 
        list.removeFirst(); 
        System.out.println("consuming values"+j); 
        notify(); 
       } 
     } 
    } 

Antwort

0

Wenn ich diesen Code ausführen, erzeugt es eine NoSuchElementException. Das Problem besteht darin, dass nach dem Notify der Consume-Thread den Monitor nicht freigibt, sodass die Produktion nie fortgesetzt wird. Eine einfache Lösung für Ihren Code zu schreiben, wäre Ihr in einer gnädiger Weise konsumieren, sagen wie folgt aus:

public void consume() { 
    int remaining = 5; 
    while (remaining > 0) { 
     synchronized (this) { 
      if (!list.isEmpty()) { 
       System.out.println(list + "list" + "consumer"); 
       final int value = list.removeFirst(); 
       System.out.println("consuming value " + value); 
       remaining--; 
       notify(); 
      } 
     } 
    } 
} 

Hinweis, wie die Synchronisation innerhalb der Schleife auftritt, das heißt, es wird bei jeder Iteration freigegeben. Dies gibt dem Produktfaden eine Chance, es zu greifen. Der Grund dafür, dass der product-Thread ihn aufgibt, indem er es dem Thread erlaubt, ihn zu erhalten und festzuhalten, obwohl beide Methodensynchronisierung deklarieren, liegt daran, dass die wait-Methode die Monitorsperre aufgibt.

Verwandte Themen