Comment les méthodes wait () et notify () peuvent-elles être appelées sur des objects qui ne sont pas des threads?

Comment les méthodes wait() et notify() peuvent-elles être appelées sur des objects qui ne sont pas des threads? Cela n’a pas vraiment de sens, n’est-ce pas?

Bien sûr, cela doit avoir un sens, car les deux méthodes sont disponibles pour tous les objects Java. Quelqu’un peut-il fournir une explication? J’ai du mal à comprendre comment communiquer entre les threads en utilisant wait() et notify() .

Les verrous sont différents des threads. Le verrou est sur la structure de données à protéger. Les threads sont les éléments accédant à la structure de données. Les verrous se trouvent sur l’object structure de données afin d’empêcher les threads d’accéder à la structure de données de manière non sécurisée.

N’importe quel object peut être utilisé comme verrou insortingnsèque (c’est-à-dire utilisé conjointement avec synchronized ). De cette façon, vous pouvez protéger l’access à tout object en ajoutant le modificateur synchronisé aux méthodes qui accèdent aux données partagées. (Ce n’est pas une bonne idée, car cela permet à tout thread pouvant accéder à l’object d’acquérir son verrou, même s’il n’appelle aucune méthode dessus; il est préférable de garder le verrou en tant que membre privé de la structure de données en cours de locking). pour que l’access y soit limité.)

wait et notify sont appelés sur les objects utilisés comme verrous. Le verrou est un sharepoint communication partagé:

  • Lorsqu’un thread qui a un verrou appelle notifyAll , les autres threads en attente sur ce même verrou sont notifiés. Lorsqu’un thread qui a un verrou appelle des notify , l’un des threads en attente sur le même verrou est notifié.

  • Lorsqu’un thread qui a un appel de locking wait , le thread libère le verrou et rest en sumil jusqu’à ce qu’il reçoive une notification, ou b) qu’il se réveille arbitrairement (le “réveil parasite”); le thread en attente rest bloqué dans l’appel à attendre jusqu’à ce qu’il se réveille pour l’une des deux raisons suivantes, puis le thread doit reprendre le verrou avant de pouvoir quitter la méthode wait.

Voir le didacticiel Oracle sur les blocs gardés , la classe Drop est la structure de données partagée, les threads utilisant les exécutables Producer et Consumer y accèdent. Le locking de l’object Drop contrôle la manière dont les threads accèdent aux données de l’object Drop.

Les threads sont utilisés comme des verrous dans l’implémentation de la JVM. Il est conseillé aux développeurs d’applications d’éviter d’utiliser des threads comme verrous. Par exemple, la documentation de Thread.join dit:

Cette implémentation utilise une boucle des appels this.wait conditionnés sur this.isAlive. En tant que thread se termine, la méthode this.notifyAll est appelée. Il est recommandé aux applications de ne pas utiliser wait, notify ou notifyAll on Thread.

Vous pouvez utiliser wait() et notify() pour synchroniser votre logique. Par exemple

 synchronized (lock) { lock.wait(); // Will block until lock.notify() is called on another thread. } // Somewhere else... ... synchronized (lock) { lock.notify(); // Will wake up lock.wait() } 

avec lock étant le membre de la classe Object lock = new Object();

Vous pouvez arrêter votre thread pour le temps comme vous le souhaitez en utilisant la méthode statique de classe Thread sleep() .

 public class Main { //some code here //Thre thread will sleep for 5sec. Thread.sleep(5000); } 

Si vous voulez arrêter certains objects, vous devez appeler cette méthode dans les blocs syncronized .

 public class Main { //some code public void waitObject(Object object) throws InterruptedException { synchronized(object) { object.wait(); } } public void notifyObject(Object object) throws InterruptedException { synchronized(object) { object.notify(); } } 

}

PS je suis sory si je me trompe comprendre votre question (anglais n’est pas mon natif)

Pensez à un exemple concret , une salle de bain . Lorsque vous voulez utiliser les canvasttes de votre bureau, vous avez deux options pour vous assurer que personne ne viendra aux canvasttes une fois que vous l’utiliserez.

  1. Verrouillez la porte de la salle de bain pour que tout le monde sache que quelqu’un d’autre l’utilise lorsqu’il tente d’ouvrir la porte
  2. Rendez-vous à chaque personne au bureau, enfermez-les dans une chaise (ou à une table ou autre), allez aux canvasttes.

Quelle option prendriez-vous?

Oui, c’est pareil dans le Javaland!

Donc, dans l’histoire ci-dessus,

  • Washroom = Objet que vous voulez verrouiller (que vous devez utiliser uniquement)
  • Vos collègues de travail = autres sujets que vous souhaitez garder à l’écart

Donc, comme dans la vraie vie, lorsque vous avez des affaires privées, vous verrouillez cet object. Et quand vous en avez fini avec cet object, vous lâchez la serrure!

(Oui oui!, C’est une description très simple de ce qui se passe. Bien sûr, le vrai concept est légèrement différent de cela, mais c’est un sharepoint départ)

Dans Java, tous les objects implémentent ces deux méthodes, bien évidemment, s’il n’ya pas de moniteur, ces deux méthodes sont inutiles.

Lorsque vous mettez du code dans un bloc synchronisé:

  sychronized(lock){...} 

un thread souhaitant effectuer ce qui est à l’intérieur de ce bloc acquiert d’abord un verrou sur un object et un seul thread à la fois peut exécuter le code verrouillé sur le même object. Tout object peut être utilisé comme verrou mais vous devez faire attention à choisir l’object correspondant à la scope. Par exemple, lorsque plusieurs threads ajoutent quelque chose au compte et qu’ils ont tous du code responsable de cela dans un bloc comme:

 sychronized(this){...} 

alors aucune synchronisation n’a lieu car ils sont tous bloqués sur un object différent. Au lieu de cela, vous devez utiliser un object de compte comme verrou. Considérons maintenant que ces threads ont également une méthode pour se retirer d’un compte. Dans ce cas, une situation peut se produire lorsqu’un thread souhaitant retirer quelque chose rencontre un compte vide. Il devrait attendre qu’il y ait de l’argent et libérer le verrou sur les autres threads pour éviter un blocage. Voilà ce que sont les méthodes d’attente et de notification. Dans cet exemple, un thread qui rencontre un compte vide libère le verrou et attend le signal de certains threads qui effectuent le repository:

 while(balance < amountToWithdraw){ lock.wait(); } 

Quand un autre thread dépose de l'argent, il signale aux autres threads qui attendent sur le même verrou. (bien sûr, le code responsable des repositorys et des retraits doit être synchronisé sur le même verrou pour que cela fonctionne et pour empêcher la corruption des données).

 balance += amountToDeposit; lock.signallAll; 

Comme vous le voyez, les méthodes wait et notify n'ont de sens que dans les blocs ou méthodes synchronisés.

  1. Attendre et notifier ne concerne pas uniquement les méthodes normales ou l’utilitaire de synchronisation, mais plutôt un mécanisme de communication entre deux threads en Java. Et la classe Object est l’endroit approprié pour les rendre disponibles pour chaque object si ce mécanisme n’est pas disponible via un mot clé Java tel que synchronisé. Rappelez-vous que synchronized et wait notify sont deux zones différentes et ne confondent pas qu’elles sont identiques ou liées. Synchronisé consiste à fournir une exclusion mutuelle et à assurer la sécurité des threads de la classe Java comme la condition de concurrence, tandis que wait et notify sont des mécanismes de communication entre deux threads.
  2. Les verrous sont disponibles par object, ce qui est une autre raison pour laquelle wait et notify est déclaré dans la classe Object plutôt que dans la classe Thread.
  3. Dans Java, pour entrer la section critique du code, les threads doivent être verrouillés et ils attendent le locking, ils ne savent pas quel thread contient le verrou, ils savent simplement que le verrou est bloqué par un thread et qu’ils doivent attendre le locking au lieu de savoir thread est à l’intérieur du bloc synchronisé et leur demande de libérer le verrou. Cette analogie correspond à wait et notify étant sur la classe d’objects plutôt que sur le thread en Java.

Analogie: un thread Java est un utilisateur et la canvastte est un bloc de code que le thread souhaite exécuter. Java permet de verrouiller le code d’un thread en cours d’exécution à l’aide du keywokd synchronisé, et d’attendre que le premier thread soit terminé. Ces autres threads sont placés dans l’état d’attente. Java n’est pas aussi juste que la station-service car il n’y a pas de queue pour les threads en attente. N’importe quel thread en attente peut recevoir le moniteur, quel que soit l’ordre dans lequel ils l’ont demandé. La seule garantie est que tous les threads pourront utiliser le code surveillé tôt ou tard.

La source

Si vous regardez le code producteur et consommateur suivant:
sharedQueue object sert à la communication entre producer and consumer threads du producer and consumer .

 import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class ProducerConsumerSolution { public static void main(Ssortingng args[]) { Vector sharedQueue = new Vector(); int size = 4; Thread prodThread = new Thread(new Producer(sharedQueue, size), "Producer"); Thread consThread = new Thread(new Consumer(sharedQueue, size), "Consumer"); prodThread.start(); consThread.start(); } } class Producer implements Runnable { private final Vector sharedQueue; private final int SIZE; public Producer(Vector sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { for (int i = 0; i < 7; i++) { System.out.println("Produced: " + i); try { produce(i); } catch (InterruptedException ex) { Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex); } } } private void produce(int i) throws InterruptedException { // wait if queue is full while (sharedQueue.size() == SIZE) { synchronized (sharedQueue) { System.out.println("Queue is full " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } // producing element and notify consumers synchronized (sharedQueue) { sharedQueue.add(i); sharedQueue.notifyAll(); } } } class Consumer implements Runnable { private final Vector sharedQueue; private final int SIZE; public Consumer(Vector sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { while (true) { try { System.out.println("Consumed: " + consume()); Thread.sleep(50); } catch (InterruptedException ex) { Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex); } } } private int consume() throws InterruptedException { //wait if queue is empty while (sharedQueue.isEmpty()) { synchronized (sharedQueue) { System.out.println("Queue is empty " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } //Otherwise consume element and notify waiting producer synchronized (sharedQueue) { sharedQueue.notifyAll(); return (Integer) sharedQueue.remove(0); } } } 

La source

Msgstr “” “Cette méthode ne doit être appelée que par un thread propriétaire du moniteur de cet object.” Donc, je pense que vous devez vous assurer qu’il existe un thread qui est le moniteur sur l’object.