Comment utiliser wait et notify en Java sans IllegalMonitorStateException?

J’ai 2 masortingces et je dois les multiplier puis 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 . Je dois donc l’imprimer par ordre. Donc mon idée est de faire en sorte que le thread d’imprimante attende que le multiplyThread indique que la bonne cellule est prête à être imprimée, puis l’ printerThread imprimera la cellule et reviendra à l’attente, etc.

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 = maxActions) { countNumOfActions = 0; maxActions = randomize(); yield(); } } isFinished[rowNum][colNum] = true; notify(); } 

Fil 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 masortingx 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) 

la ligne 49 dans multiplyThread est la “notify ()” .. Je pense que je dois utiliser la synchronisation différemment mais je ne sais pas comment.

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

    Pour pouvoir appeler notify (), vous devez vous synchroniser sur le même object.

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

    Lors de l’utilisation des méthodes wait and notify ou notifyAll en Java, les éléments suivants doivent être mémorisés:

    1. Utilisez notifyAll au lieu de notify si vous prévoyez que plusieurs threads attendent un verrou.
    2. Les méthodes wait et notify doivent être appelées dans un contexte synchronisé . Voir le lien pour une explication plus détaillée.
    3. Appelez toujours la méthode wait() dans une boucle car si plusieurs threads attendent un verrou et que l’un d’eux obtient le verrou et réinitialise la condition, les autres threads doivent vérifier la condition après leur réveil pour voir s’ils doivent attendre encore ou peut commencer le traitement.
    4. Utilisez le même object pour appeler la méthode wait() et notify() ; Chaque object a son propre verrou, donc appeler wait() sur l’object A et notify() sur l’object B n’a aucun sens.

    Avez-vous besoin de l’envoyer du tout? Je me demande quelle est la taille de vos masortingces, et s’il y a un avantage à avoir une impression de thread alors que l’autre fait la multiplication.

    Peut-être serait-il utile de mesurer cette fois avant de faire le travail de filetage relativement complexe?

    Si vous avez besoin de l’enfiler, je créerais des threads pour effectuer la multiplication des cellules (peut-être le nombre de cœurs disponibles), puis utilisez le mécanisme ExecutorService and Future pour envoyer 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 niveau supérieur (ce qui devrait vous simplifier la vie). Ecrivez les résultats dans une masortingce de réception, puis imprimez-les simplement une fois toutes vos tâches futures terminées.

    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(Ssortingng resp) qui sera appelé par BlackBoxClass après un temps inconnu.

    Le stream est simple:

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

    Disons que nous ne soaps pas ce qui se passe avec BlackBoxClass et quand nous devrions obtenir une réponse, mais vous ne voulez pas continuer votre code tant que vous n’avez pas reçu de réponse ou, en d’autres termes, vous onResponse recevez onResponse appel onResponse . 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 Ssortingng 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(Ssortingng resp){ mResponse = resp; sync.doNotify(); } } 

    Vous ne pouvez appeler que notifier des objects sur lesquels vous possédez leur moniteur. Donc, vous avez besoin de quelque chose comme

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

    notify() doit également être synchronisé

    Je vais vous donner un exemple simple pour vous montrer comment utiliser wait et notify en Java. Je vais donc créer deux classes nommées ThreadA & ThreadB . ThreadA appellera ThreadB.

     public class ThreadA { public static void main(Ssortingng[] args){ ThreadB b = new ThreadB();//<----Create Instance for seconde class b.start();//<--------------------Launch thread synchronized(b){ try{ System.out.println("Waiting for b to complete..."); b.wait();//<-------------WAIT until the finish thread for class B finish }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("Total is: " + b.total); } } } 

    et pour la classe ThreadB:

     class ThreadB extends Thread{ int total; @Override public void run(){ synchronized(this){ for(int i=0; i<100 ; i++){ total += i; } notify();//<----------------Notify the class wich wait until my finish //and tell that I'm finish } } } 

    nous pouvons appeler notifier pour reprendre l’exécution des objects en attente comme

     public synchronized void guardedJoy() { // This guard only loops once for each special event, which may not // be the event we're waiting for. while(!joy) { try { wait(); } catch (InterruptedException e) {} } System.out.println("Joy and efficiency have been achieved!"); } 

    reprendre cela en invoquant la notification sur un autre object de même classe

     public synchronized notifyJoy() { joy = true; notifyAll(); } 

    Utilisation simple si vous voulez Comment exécuter des threads alternativement: –

     public class MyThread { public static void main(Ssortingng[] args) { final Object lock = new Object(); new Thread(() -> { try { synchronized (lock) { for (int i = 0; i <= 5; i++) { System.out.println(Thread.currentThread().getName() + ":" + "A"); lock.notify(); lock.wait(); } } } catch (Exception e) {} }, "T1").start(); new Thread(() -> { try { synchronized (lock) { for (int i = 0; i <= 5; i++) { System.out.println(Thread.currentThread().getName() + ":" + "B"); lock.notify(); lock.wait(); } } } catch (Exception e) {} }, "T2").start(); } } 

    responce: -

     T1:A T2:B T1:A T2:B T1:A T2:B T1:A T2:B T1:A T2:B T1:A T2:B 

    Pour ce problème particulier, pourquoi ne pas stocker vos différents résultats dans des variables et, lorsque le dernier de vos threads est traité, vous pouvez imprimer dans le format de votre choix. Ceci est particulièrement utile si vous voulez utiliser votre historique de travail dans d’autres projets.

    Cela ressemble à une situation de modèle producteur-consommateur. Si vous utilisez Java 5 ou plus, vous pouvez envisager d’utiliser la queue de blocage (java.util.concurrent.BlockingQueue) et laisser le travail de coordination des threads à l’implémentation du framework / api sous-jacente. Voir l’exemple de java 5: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html ou java 7 (même exemple): http: // docs. oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

    Vous avez correctement protégé votre bloc de code lorsque vous appelez la méthode wait() en utilisant synchronized(this) .

    Mais vous n’avez pas pris les mêmes précautions lorsque vous appelez la méthode notify() sans utiliser le bloc guarded: synchronized(this) ou synchronized(someObject)

    Si vous vous référez à la page de documentation d’Oracle sur la classe Object , qui contient les méthodes wait() , notify() , notifyAll() , vous pouvez voir ci-dessous les précautions de ces trois méthodes.

    Cette méthode ne doit être appelée que par un thread propriétaire du moniteur de cet object

    Beaucoup de choses ont été changées au cours des 7 dernières années et examinons d’autres alternatives à la synchronized questions SE ci-dessous:

    Pourquoi utiliser un ReentrantLock si on peut utiliser synchronisé (this)?

    Synchronisation vs locking

    Évitez de synchroniser (ceci) en Java?