132 votes

Comment utiliser wait et notify en Java ?

J'ai 2 matrices et j'ai besoin de les multiplier puis d'imprimer les résultats de chaque cellule. Dès qu'une cellule est prête, je dois l'imprimer, mais par exemple, je dois imprimer la cellule [0][0] avant la cellule [2][0] même si le résultat de [2][0] est prêt en premier. J'ai donc besoin de l'imprimer par ordre. Mon idée est donc de faire attendre le thread de l'imprimante jusqu'à ce que le résultat de [2][0] soit prêt en premier. multiplyThread lui signale que la bonne cellule est prête à être imprimée, puis le programme printerThread imprimera la cellule et retournera à l'attente et ainsi de suite

J'ai donc ce fil qui fait la multiplication :

public void run() 
{
    int countNumOfActions = 0; // How many multiplications have we done
    int maxActions = randomize(); // Maximum number of actions allowed

    for (int i = 0; i < size; i++)
    {       
        result[rowNum][colNum] = result[rowNum][colNum] + row[i] * col[i];
        countNumOfActions++;
        // Reached the number of allowed actions
        if (countNumOfActions >= maxActions)
        {
            countNumOfActions = 0;
            maxActions = randomize();
            yield();
        }   
    }
    isFinished[rowNum][colNum] = true;
    notify();
}

Thread qui imprime le résultat de chaque cellule :

public void run()
{
    int j = 0; // Columns counter
    int i = 0; // Rows counter
    System.out.println("The result matrix of the multiplication is:");

    while (i < creator.getmThreads().length)
    {
        synchronized (this)
        {
            try 
            {
                this.wait();
            } 
            catch (InterruptedException e1) 
            {
            }
        }
        if (creator.getmThreads()[i][j].getIsFinished()[i][j] == true)
        {
            if (j < creator.getmThreads()[i].length)
            {
                System.out.print(creator.getResult()[i][j] + " ");
                j++;
            }
            else
            {
                System.out.println();
                j = 0;
                i++;
                System.out.print(creator.getResult()[i][j] + " ");
            }
        }
    }

Maintenant, il me jette ces exceptions :

Exception in thread "Thread-9" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-6" Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-5" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-8" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-7" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-11" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-10" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-12" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)

ligne 49 dans multiplyThread Je pense que je dois utiliser la fonction synchronisée différemment, mais je ne sais pas comment.

Si quelqu'un peut aider ce code à fonctionner, je l'apprécierai vraiment.

Merci d'avance,

Greg

219voto

Bombe Points 34185

Pour pouvoir appeler notifier() vous devez vous synchroniser sur le même objet.

synchronized (someObject) {
    someObject.wait();
}

/* different thread / object */
synchronized (someObject) {
    someObject.notify();
}

64voto

Jackob Points 411

Pendant l'utilisation du wait et notify ou notifyAll en Java, il faut se rappeler les points suivants :

  1. Utilisez notifyAll au lieu de notify si vous vous attendez à ce que plusieurs threads soient en attente d'un verrou.
  2. Le site wait et notify les méthodes doivent être appelées dans un contexte synchronisé . Voir le lien pour une explication plus détaillée.
  3. Appelez toujours le wait() dans une boucle car si plusieurs threads attendent un verrou et que l'un d'entre eux l'obtient et réinitialise la condition, les autres threads doivent vérifier la condition après leur réveil pour voir s'ils doivent attendre à nouveau ou s'ils peuvent commencer le traitement.
  4. Utilisez le même objet pour appeler wait() et notify() chaque objet a son propre verrou, donc appeler la méthode wait() sur l'objet A et notify() sur l'objet B n'aura aucun sens.

21voto

Brian Agnew Points 143181

Avez-vous besoin de filtrer tout cela ? Je me demande quelle est la taille de vos matrices, et s'il y a un avantage à ce qu'un thread imprime pendant que l'autre effectue la multiplication.

Peut-être vaudrait-il la peine de mesurer ce temps avant d'effectuer le travail relativement complexe d'enfilage ?

Si vous avez besoin de le filtrer, je créerais "n" threads pour effectuer la multiplication des cellules (peut-être que "n" est le nombre de cœurs dont vous disposez), puis j'utiliserais la fonction ExecutorService et Futur mécanisme permettant de répartir plusieurs multiplications simultanément.

De cette façon, vous pouvez optimiser le travail en fonction du nombre de cœurs, et vous utilisez les outils de threading Java de plus haut niveau (ce qui devrait vous faciliter la vie). Inscrivez les résultats dans une matrice de réception, puis imprimez-la simplement une fois que toutes vos tâches futures sont terminées.

14voto

Maxim Shoustin Points 20035

Disons que vous avez une application "boîte noire" avec une classe nommée BlackBoxClass qui a la méthode doSomething(); .

De plus, vous avez un observateur ou un auditeur nommé onResponse(String resp) qui sera appelé par BlackBoxClass après un temps inconnu.

Le flux est simple :

private String mResponse = null; 
 ...
BlackBoxClass bbc = new BlackBoxClass();
   bbc.doSomething();
...
@override
public void onResponse(String resp){        
      mResponse = resp;       
}

Disons que nous ne savons pas ce qu'il se passe avec BlackBoxClass et quand nous devrions obtenir la réponse, mais vous ne voulez pas continuer votre code jusqu'à ce que vous obteniez la réponse ou, en d'autres termes, vous obtenez onResponse appel. Ici entre 'Synchronize helper' :

public class SyncronizeObj {
public void doWait(long l){
    synchronized(this){
        try {
            this.wait(l);
        } catch(InterruptedException e) {
        }
    }
}

public void doNotify() {
    synchronized(this) {
        this.notify();
    }
}

public void doWait() {
    synchronized(this){
        try {
            this.wait();
        } catch(InterruptedException e) {
        }
    }
}
}

Maintenant, nous pouvons mettre en œuvre ce que nous voulons :

public class Demo {

private String mResponse = null; 
 ...
SyncronizeObj sync = new SyncronizeObj();

public void impl(){

BlackBoxClass bbc = new BlackBoxClass();
   bbc.doSomething();

   if(mResponse == null){
      sync.doWait();
    }

/** at this momoent you sure that you got response from  BlackBoxClass because
  onResponse method released your 'wait'. In other cases if you don't want wait too      
  long (for example wait data from socket) you can use doWait(time) 
*/ 
...

}

@override
public void onResponse(String resp){        
      mResponse = resp;
      sync.doNotify();       
   }

}

7voto

PaulJWilliams Points 11641

Vous ne pouvez appeler notify sur des objets que si vous possédez leur moniteur. Vous avez donc besoin de quelque chose comme

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X