2017-07-07 3 views
0

je lisais ceci: How to use wait and notify in Java?code ne fonctionne pas après appel synchronisé (communication) Java en utilisant le multithreading

Je veux mettre en œuvre un exemple d'attente/notify pour Producteur/modèle de consommation en Java avec Threads . Le consommateur est un serveur avec des objets stockés dans la liste. Peut ajouter/supprimer de cette liste.

Le producteur envoie des données (en utilisant PipedInputStream/PipedOutputStream) uniquement si Consumer Server a stocké des objets (entiers), sinon le producteur est arrêté. Lorsque le serveur a de nouveau Objets le producteur commence à envoyer des données.

Le problème ressusciterai, quand je l'appelle les prochaines méthodes

public void addInteger() { 
     new Thread (new Runnable() { 
     public void run() { 
      try { 
      System.out.println ("Add before size:" + lConsumerClient.size()); 
      lConsumerClient.add((int)(Math.random()*100.0)); 
      synchronized(oSignalExternal) { 
       oSignalExternal.notify(); 
      } 
      System.out.println ("Add after size:" + lConsumerClient.size()); 
      } catch (Exception e) { e.printStackTrace(); } 
     } 
     }).start(); 
    } 

    public void removeFirst() { 
     new Thread (new Runnable() { 
     public void run() { 
      try { 
      System.out.println ("Remove before size:" + lConsumerClient.size()); 
      if (hasInteger()) { 
       lConsumerClient.remove(0); 
      } 
      synchronized(oSignalExternal) { 
       oSignalExternal.notify(); 
      } 
      System.out.println ("Remove after size:" + lConsumerClient.size()); 
      } catch (Exception e) { e.printStackTrace(); } 
     } 
     }).start(); 
    } 

La sortie:

Add before size:0 
Add after size:1 
     i:0 ->18 =218 
     i:0 ->18 =218 
Add before size:1 
     i:0 ->18 =218 
     i:1 ->90 =290 
     i:0 ->18 =218 
     i:1 ->90 =290 
Add before size:2 
     i:0 ->18 =218 
     i:1 ->90 =290 
     i:2 ->76 =276 
Add before size:3 
     i:0 ->18 =218 
     i:1 ->90 =290 
     i:2 ->76 =276 
     i:3 ->43 =243 
Remove before size:4 
Remove before size:3 
Remove before size:2 
     i:0 ->43 =243 
     i:0 ->43 =243 
Remove before size:1 
ExtSynchro$ExtClient sleeping 
Remove after size:0 
Remove after size:0 
Remove after size:0 
ExtSynchro$ExtClient sleeping 
Add after size:0 
Add after size:0 
Add after size:0 
Remove after size:0 

L'attente et aviser travaille.

Je veux savoir pourquoi, après appel:

synchronized(oSignalExternal) { 
    oSignalExternal.notify(); 
} 

Aucun code est exécuté?

Voici le code complet

import java.awt.*; 
import java.awt.event.*; 
import java.io.*; 
import java.util.*; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.ArrayBlockingQueue; 

import javax.swing.*; 
public class ExtSynchro extends JFrame { 

    JButton jbSync = new JButton("Sync"); 
    JButton jbPlus = new JButton("+"); 
    JButton jbMinus = new JButton("-"); 
    JButton jbStop = new JButton("Stop"); 

    Object oSignalExternal = new Object(); 
    ExtServer exConsumerServer; 
    ExtClient exProducerClient; 
    PipedInputStream pSnk = new PipedInputStream(); 
    PipedOutputStream pSrc = new PipedOutputStream(); 
    static final String NL = System.getProperty("line.separator"); 

    public ExtSynchro() { 
    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 

    jbSync.addActionListener((ActionEvent e) -> { 
     try { pSrc.connect(pSnk); } catch (IOException ex) {} 
     exConsumerServer = new ExtServer(); 
     exProducerClient = new ExtClient(); 
     exConsumerServer.start(); 
     exProducerClient.start(); 
    }); 

    jbPlus.addActionListener((ActionEvent e) -> { 
     exConsumerServer.addInteger(); 
    }); 

    jbMinus.addActionListener((ActionEvent e) -> { 
     exConsumerServer.removeFirst(); 
    }); 

    jbStop.addActionListener((ActionEvent e) -> { 
     exConsumerServer.stopThread(); 
     exProducerClient.stopThread(); 
     exConsumerServer = null; 
     exProducerClient = null; 
    }); 

    JPanel jpButtons = new JPanel(); 
    jpButtons.setLayout(new BoxLayout(jpButtons, BoxLayout.PAGE_AXIS)); 
    jpButtons.add(jbSync); 
    jpButtons.add(jbPlus); 
    jpButtons.add(jbMinus); 
    jpButtons.add(jbStop); 
    add(jpButtons); 
    pack(); 
    } 

    public static void main(String args[]) { 
    EventQueue.invokeLater(() -> { 
     new ExtSynchro().setVisible(true); 
    }); 
    } 

    class ExtClient extends Thread { 
    private volatile boolean bRunning; 

    @Override public void run() { 
     bRunning = true; 
     while (bRunning) { 
     try { 
      synchronized(oSignalExternal) { 
      try { 
       while (exConsumerServer.hasInteger()) { 
       pSrc.write(200); 
       try { Thread.sleep(3000); } catch (InterruptedException ex) { } 
       } 
       System.out.println(getClass().getName() + "\tsleeping"); 
       oSignalExternal.wait(); 
      } catch (InterruptedException e2) {} 
      if (!bRunning) break; // To exit from synchronized 
      } 
     } catch (IOException e) { 
      bRunning = false; 
     } 
     } 
     System.out.println(getClass().getName() + "\tfinishing"); 
    } 

    public void stopThread() { 
     bRunning = false; 
     synchronized(oSignalExternal) { 
     oSignalExternal.notify(); 
     } 
    } 
    }; 

//The Consumer Server. 

    class ExtServer extends Thread { 
    private volatile boolean bRunning; 
    //BlockingQueue<Integer> lConsumerClient =new ArrayBlockingQueue<>(10); 
    java.util.List<Integer> lConsumerClient = Collections.synchronizedList(new ArrayList<>(4)); 


    @Override public void run() { 
     bRunning = true; 
     while (bRunning) { 
     int iRd; 
     try { 
      while ((iRd = pSnk.read()) != -1) { 
      for (int i = 0; i < lConsumerClient.size(); i++) { 
       int n = lConsumerClient.get(i); 
       System.out.println ("\t\ti:" + i + " ->" + n +"\t=" + (n + iRd)); 
      } 
      } 
     } catch (IOException e) {} 
     } 
     System.out.println(getClass().getName() + "\tfinishing"); 
    } 

    public void addInteger() { 
     new Thread (new Runnable() { 
     public void run() { 
      try { 
      System.out.println ("Add before size:" + lConsumerClient.size()); 
      lConsumerClient.add((int)(Math.random()*100.0)); 
      synchronized(oSignalExternal) { 
       oSignalExternal.notify(); 
      } 
      System.out.println ("Add after size:" + lConsumerClient.size()); 
      } catch (Exception e) { e.printStackTrace(); } 
     } 
     }).start(); 
    } 

    public void removeFirst() { 
     new Thread (new Runnable() { 
     public void run() { 
      try { 
      System.out.println ("Remove before size:" + lConsumerClient.size()); 
      if (hasInteger()) { 
       lConsumerClient.remove(0); 
      } 
      synchronized(oSignalExternal) { 
       oSignalExternal.notify(); 
      } 
      System.out.println ("Remove after size:" + lConsumerClient.size()); 
      } catch (Exception e) { e.printStackTrace(); } 
     } 
     }).start(); 
    } 

    public boolean hasInteger() { 
     return lConsumerClient.size() > 0; 
    } 
    public void stopThread() { 
     bRunning = false; 
     try { pSrc.close();pSnk.close(); } catch (IOException e) {} 
    } 
    }; 
} 
+4

C'est énormément de code que vous attendez de nous. S'il vous plaît couper à un [mcve]. –

+2

Et aussi: "Je suis un novice" alors restez loin de 'wait()' et 'notify()'. Vous pouvez faire des choses incroyables si vous savez ce que vous faites, mais ils sont difficiles à utiliser correctement. Laissez-les (et en fait la plupart du multithreading) jusqu'à ce que vous ayez une compréhension beaucoup plus solide de Java. (Je peux honnêtement dire que je ne pense pas avoir jamais besoin de les utiliser pour les réels: les classes de plus haut niveau dans 'java.util.concurrent' sont * beaucoup * plus faciles à utiliser correctement). –

+0

Il n'y a pas de main, que couper et coller accomplir? – matt

Répondre

0

Cette section brise votre code

synchronized(oSignalExternal) { 
     try { 
     while (exConsumerServer.hasInteger()) { 
      pSrc.write(200); 
      try { Thread.sleep(3000); } catch (InterruptedException ex) { } 
     } 
     System.out.println(getClass().getName() + "\tsleeping"); 
     oSignalExternal.wait(); 
     } catch (InterruptedException e2) {} 
     if (!bRunning) break; // To exit from synchronized 
    } 

vous ne retirez pas d'éléments, de sorte que votre exConsumerServer a toujours des éléments. Utilisez une file d'attente bloquante.

BlockingQueue<Integer> valuesToTake = new LinkedBlockingQueue(); 

Ensuite, votre méthode d'exécution devient. Ensuite, il vous suffit de publier des entiers sur les valeurs à prendre et le client les enverra.

+0

@Anita vous ajoutez add entier est en cours d'exécution sur l'EDT, et il bloque votre application. Vous devez effectuer cette action hors de l'EDT. C'est pourquoi vous utiliseriez une file d'attente. Vous soumettez une action à un exécuteur ou l'importez dans une file d'attente et le thread correspondant en prend soin. – matt

+0

Merci, maintenant je comprends le problème. Pour cette raison, j'ai changé la question. En examinant 'BlockingQueue' et' LinkedBlockingQueue' je ne peux pas voir comme 'ValuesStored.peek (Index)' pour examiner tous les objets stockés sans enlever l'objet ... 'take()' Récupère et supprime ... – Anita