2016-07-24 31 views
4

Ich habe ein ConsumerProducer-Objekt, auf dem ich Sperre von zwei verschiedenen Threads erwerben möchte. Die Klasse ist wie folgt:wait()/notify() funktioniert nicht richtig

public class ConsumerProducer { 

    public String stringPool = null; 

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

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

} 

Der Faden impl Klasse ist wie folgt:

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

} 

Aber wenn ich den Code ausführen wird es eine Art Sackgasse gegenüber und es klemmt Druck wie

Putting: Counter3 
notify from Consumer 

Etwas läuft furchtbar falsch, aber ich kann mich nicht identifizieren. Bitte helfen Sie.

+0

Ich versuche normalerweise zu Vermeiden Sie Wartezeiten/Benachrichtigungen, da sie schwieriger zu verstehen sind als Dinge wie CountDownLatch und CyclicBarrier . –

Antwort

1

Ihr Kunde erledigt den Job des Produzenten und der Produzent erledigt den Job des Konsumenten. Tauschen Sie ihre Verantwortung aus und ändern Sie die Bedingung, um zu warten. Bitte beachten Sie den folgenden Code.

  1. Verbraucher wird warten, wenn es nichts zu bekommen gibt und er wird die Sperre von cp freigeben. Damit hat der Produzent die Chance, in den synchronisierten Block zu gehen.
  2. Produzent produziert nur, wenn es nichts gibt oder er wird warten. Danach wird er die Sperre von cp freigeben. So hat der Verbraucher die Chance, in den synchronisierten Block zu gehen.
  3. Verbraucher ist, wer Dinge wegbekommen.
  4. Produzent ist, wer Dinge zu Tisch legen.
  5. Nach Ihrem Kommentar. Sie möchten Counter von 1 bis 5 setzen, also sollten Sie i ++ nur im Producer-Thread hinzufügen. Wie können Sie den Anstieg in beiden Threads steuern?
  6. Sie nicht beurteilen, ob es Verbraucher oder Produzent ist die get() von cp Objekt aufgerufen wird, sondern auf stringPool null zuweisen. Es ist offensichtlich falsch und wird dazu führen, dass der Verbraucher vom öffentlichen Raum null bekommt. Ich füge eine neue Methode clearString() hinzu, die den öffentlichen Platz auf null setzt, nur wenn der Verbraucher das Produkt infiziert hat.

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

Auch die ConsumerProducer-Klasse.

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

Danke @Gearon. Der Stillstand ist weg. Die Ausgabe ist jedoch nicht wie erwartet. Ausgang: 'Putting: Counter1 von Produzenten benachrichtigt bekommen: null von Consumer benachrichtigen Putting: Counter3 von Produzenten benachrichtigen bekommen: Counter3 benachrichtigt Consumer Putting: Counter5 von Produzenten benachrichtigt bekommen: Counter5 benachrichtigen von Consumer' Inkonsistent obwohl. –

+0

Erwartete Ausgabe: 'Putting: Counter1 von Produzenten benachrichtigt bekommen: Counter1 von Consumer benachrichtigen Putting: Counter2 von Produzenten benachrichtigt bekommen: Counter2 von Consumer benachrichtigen Putting: Counter3 von Produzenten benachrichtigt bekommen: Counter3 benachrichtigen von Consumer Einlochen: Counter4 benachrichtigt Producer bekommen: Counter4 von Consumer benachrichtigen Putting: Counter5 von Produzenten benachrichtigen bekommen: Counter5 benachrichtigen von Verbraucher " –

+0

@AnirbanB. Bitte überprüfe meine Updates. Vielen Dank. – Gearon

0

Aktualisiert Code ist hier: ConsumerProducer.java:
public class 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 public class WaitNotifyTest implementiert 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(); 
    } 

}