2016-07-24 1 views
4

J'ai un objet ConsumerProducer sur lequel je veux acquérir un verrou à partir de deux threads différents. La classe est comme ci-dessous:wait()/notify() ne fonctionne pas correctement

public class ConsumerProducer { 

    public String stringPool = null; 

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

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

} 

La classe de fil impl est comme ci-dessous:

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

} 

Mais quand je lance le code, il est confronté à une sorte d'impasse et il est l'impression coincé comme

Putting: Counter3 
notify from Consumer 

Quelque chose va terriblement mal mais je ne suis pas capable de m'identifier. S'il vous plaît aider.

+0

J'essaie habituellement évitez d'attendre/notifiez parce qu'il est plus difficile de raisonner sur des choses comme CountDownLatch et CyclicBarrier . –

Répondre

1

Votre consommateur fait le travail du producteur et le producteur fait le travail du consommateur. Echangez leur responsabilité et modifiez la condition d'attente. Veuillez vous référer au code ci-dessous.

  1. Le consommateur attendra quand il n'y a rien à obtenir et il libérera le verrou de cp. Donc, ce producteur a la chance d'aller dans le bloc synchronisé.
  2. Le producteur ne produit que lorsqu'il n'y a rien ou qu'il attendra. Après cela, il va libérer la serrure de cp. Alors ce consommateur a la chance d'aller dans le bloc synchronisé.
  3. Le consommateur est celui qui obtient des choses.
  4. Le producteur est celui qui met les choses à table.
  5. D'après votre commentaire. Vous voulez mettre Counter de 1 à 5, vous devez donc ajouter i ++ uniquement dans le thread Producer. Comment pouvez-vous contrôler son augmentation dans les deux fils?
  6. Vous ne jugez pas si c'est le consommateur ou le producteur qui appelle l'objet get() depuis cp mais attribuez la valeur null à stringPool. Il est évident que c'est faux et que le consommateur deviendra nul dans l'espace public. J'ajoute une nouvelle méthode clearString() qui mettra l'espace public à zéro seulement quand le consommateur a consommé le produit.

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

Voir aussi la classe 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

Merci @Gearon. L'impasse est partie. Cependant, la sortie n'est pas comme prévu. Sortie: 'Mettre: Compteur1 informer du producteur obtenir: null Notify consommateurs Mise: Counter3 informer du producteur obtenir: Counter3 informer de la consommation Mettre: Counter5 informer du producteur obtenir: Counter5 notify from Consumer' Inconsistent cependant. –

+0

Résultats escomptés: 'Mettre: Compteur1 informer du producteur obtenir: Compteur1 informer de la consommation Mettre: Counter2 informer du producteur obtenir: Counter2 informer de la consommation Mettre: Counter3 informer du producteur obtenir: Counter3 Notify consommateurs Mise: Counter4 informer du producteur obtenir: Counter4 informer de la consommation Mettre: Counter5 informer du producteur obtenir: Counter5 notifier de Consumer' –

+0

@AnirbanB. S'il vous plaît vérifier mes mises à jour. Merci. – Gearon

0

code mis à jour est ici: 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 implémente 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(); 
    } 

}