Pourquoi les méthodes wait()
et notify()
sont-elles déclarées dans la classe Object
, plutôt que dans la classe Thread
?
Parce que vous attendez un objet donné (ou spécifiquement son moniteur) pour utiliser cette fonctionnalité.
Je pense que vous vous trompez peut-être sur le fonctionnement de ces méthodes. Ils ne sont pas simplement à un niveau de granularité de thread, c'est-à-dire qu'il ne s'agit pas d'appeler simplement wait()
et d'être réveillé par le prochain appel à notify()
. Au lieu de cela, vous appelez toujours wait()
sur un objet spécifique et ne serez réveillé que par des appels à notify
sur cet objet.
C'est bien parce que sinon les primitives de concurrence ne seraient tout simplement pas mises à l'échelle; cela équivaudrait à avoir des espaces de noms globaux, car tout appel à notify()
n'importe où dans votre programme aurait le potentiel de gâcher tout code simultané car ils réveilleraient tous les threads bloqués lors d'un appel wait()
. D'où la raison pour laquelle vous les appelez sur un objet spécifique; il donne un contexte pour que la paire wait-notify fonctionne, donc quand vous appelez myBlockingObject.notify()
, sur un objet privé, vous pouvez être sûr que vous ne réveillerez que les threads qui appelaient des méthodes d'attente dans votre classe . Certains threads Spring qui pourraient attendre un autre objet ne seront pas réveillés par cet appel, et vice versa.
Edit: Ou pour y répondre sous un autre angle - j'attends de votre question que vous pensiez obtenir un descripteur du thread en attente et appeler notify()
on ce Thread pour le réveiller. La raison pour laquelle ce n'est pas fait de cette façon, c'est que vous devriez faire beaucoup de ménage vous-même. Le thread qui attendrait devrait publier une référence à lui-même quelque part que d'autres threads pourraient le voir; cela devrait être correctement synchronisé pour assurer la cohérence et la visibilité. Et lorsque vous voulez réveiller un fil, vous devez vous procurer cette référence, la réveiller et la supprimer d'où que vous la lisiez. Il y a beaucoup plus d'échafaudages manuels impliqués, et beaucoup plus de chances de se tromper avec cela (en particulier dans un environnement simultané) par rapport à simplement appeler myObj.wait()
dans le thread de sommeil puis myObj.notify()
in le fil waker.
La raison la plus simple et la plus évidente est que tout objet (pas seulement un thread) peut être le moniteur d'un thread. L'attente et la notification sont appelées sur le moniteur. Le thread en cours d'exécution vérifie avec le moniteur. Ainsi, les méthodes d'attente et de notification sont en objet et non en thread
Parce qu'un seul thread à la fois peut posséder le moniteur d'un objet et c'est ce moniteur que les threads attendent ou notifient. Si vous lisez javadoc pour Object.notify()
et Object.wait()
c'est décrit en détail.
Quelques autres réponses utilisent le mot "moniteur", mais aucune n'explique ce que cela signifie.
Le nom "moniteur" a été inventé il y a bien longtemps dans les années 1970, et il faisait référence à un objet qui avait son propre verrou intrinsèque et le mécanisme d'attente/notification associé. https://en.wikipedia.org/wiki/Monitor_%28synchronization%29
Vingt ans plus tard, il y a eu un bref moment dans le temps où les ordinateurs de bureau et multiprocesseurs étaient nouveaux, et il était à la mode de penser que la bonne façon de concevoir des logiciels pour eux serait de créer des programmes orientés objet dans lesquels chaque objet était un moniteur.
Il s'avère que ce n'était pas une idée aussi utile, mais ce bref moment se trouve être exactement lorsque le langage de programmation Java a été inventé.
Le mécanisme de synchronisation implique un concept - moniteur d'un objet. Lorsque wait () est appelé, le moniteur est demandé et l'exécution est suspendue jusqu'à ce que le moniteur soit acquis ou que InterruptedException se produise. Lorsque notify () est appelé, le moniteur est libéré.
Prenons un scénario si wait () et notify () ont été placés dans la classe Thread au lieu de la classe Object. À un moment donné du code, currentThread.wait()
est appelée, puis un objet anObject
est accessible.
//.........
currentThread.wait();
anObject.setValue(1);
//.........
Lorsque currentThread.wait () est appelé, le moniteur de currentThread
est demandé et aucune autre exécution n'est effectuée tant que le moniteur n'est pas acquis ou que InterruptedException ne se produit pas. Maintenant, en état d'attente, si une méthode foo()
d'un autre objet anotherObject
résidant dans currentThread
est appelée à partir d'un autre thread, elle est bloquée même si la méthode appelée foo()
n'accède pas à anObject
. Si la première méthode wait () était appelée sur anObject
, au lieu du thread lui-même, les autres appels de méthode (n'accédant pas à anObject
) sur des objets résidant dans le même thread ne resteraient pas bloqués.
Ainsi, l'appel des méthodes wait () et notify () sur la classe Object (ou ses sous-classes) fournit une plus grande concurrence et c'est pourquoi ces méthodes sont dans la classe Object, pas dans la classe Thread.
Les méthodes Wait et Notify sont utilisées pour la communication entre deux Threads en Java. La classe Object est donc un endroit correct pour les rendre disponibles pour chaque objet en Java.
Une autre raison est que les verrous sont disponibles par objet. Les threads doivent être verrouillés et ils attendent le verrouillage, ils ne savent pas quels threads tiennent le verrou à la place, ils savent simplement que le verrou est maintenu par un thread et ils devraient attendre le verrouillage au lieu de savoir quel thread se trouve dans le bloc synchronisé et leur demander de libérer fermer à clé
Lisez ici pour une explication de l'attente et notifiez.
Il serait cependant préférable de les éviter dans vos applications et d'utiliser le nouveau package Java.util.concurrent .
Je vais le dire de manière simple:
Pour appeler wait () ou notify (), vous devez posséder le moniteur d'objet - cela signifie que wait () ou notify () doit être présent dans le bloc synchronisé
synchronized(monitorObj){
monitorObj.wait() or even notify
}
C'est la raison pour laquelle ces méthodes sont présentes dans la classe d'objets
En effet, ces méthodes sont destinées à la communication inter-threads et la communication inter-thread se fait à l'aide de verrous, mais les verrous sont associés à des objets, d'où ils se trouvent dans la classe d'objets.