Je navigue souvent. En ce qui concerne la notification et la notification en Java, les gens ont souvent les déclarations suivantes:
Notify informera uniquement un objet en attente, tandis que NotifyAll averdra tous les objets en attente, et tous les objets continueront à s'exécuter.
Et, il semble qu'il y ait des exemples pour le prouver. La déclaration ci-dessus peut être considérée comme correcte ou non. La raison en est que l'un d'eux est très important. La déclaration officielle est la suivante:
Attendez, notifiez, notifiez:
Cette méthode ne doit être appelée que par un fil qui est le propriétaire de ce moniteur d'objet. Un fil peut devenir le propriétaire de ce moniteur d'objet de l'une des trois manières:
En exécutant la méthode d'instance synchrone de cet objet.
Le corps de l'instruction synchronisée est exécuté en exécutant l'instruction synchronisée sur cet objet.
Pour les objets de la classe de type, vous pouvez exécuter des méthodes statiques synchrones de la classe.
Un seul thread a un moniteur d'objet à la fois.
La déclaration ci-dessus est extraite de Javadoc. Cela signifie que dans l'appel, le moniteur d'objet (c'est-à-dire le verrouillage) doit être maintenu, ce que nous pouvons comprendre comme exécutant dans la méthode synchronisée. Ensuite, la signification implicite de cette instruction est que si vous souhaitez continuer le bloc de code contenu dans le bloc de synchronisation, vous devez réacquérir le verrou. Cette phrase est décrite dans Javadoc:
attendez
Cette méthode provoque le thread actuel (appelé T) de se placer dans l'ensemble d'attente de l'objet, puis d'abandonner toutes les exigences de synchronisation sur cet objet. À des fins de planification de threads, le fil T est désactivé et est en hibernation avant l'une des quatre situations suivantes:
Un autre thread appelle la méthode de notification de cet objet, et le thread T se trouve être éventuellement sélectionné comme thread de réveil.
Un autre thread appelle la méthode Notifyall de cet objet.
Un autre thread interrompt le fil T.
Environ le temps réel spécifié a été atteint. Cependant, si le délai d'attente est nul, le temps réel n'est pas pris en compte et le fil attendra jusqu'à ce que la notification soit obtenue.
Ensuite, le thread T est supprimé de l'ensemble d'attente de l'objet et la planification du thread est à nouveau effectuée. Le fil est ensuite en concurrence avec d'autres threads de manière conventionnelle pour obtenir le droit de se synchroniser sur l'objet; Une fois le contrôle de l'objet obtenu, toutes ses déclarations de synchronisation sur l'objet seront restaurées à leur état précédent, qui est d'appeler Wait
La situation où la méthode est. Le thread T revient ensuite de l'appel à la méthode d'attente. Par conséquent, lors du retour de la méthode d'attente, l'état de synchronisation de l'objet et du thread T est exactement le même que lors de l'appel de la méthode d'attente.
Autrement dit, la serrure doit être réapprochée, de sorte que pour Notifyall, tous les threads ont été informés. Cependant, ces threads concourront et un seul thread acquiert avec succès le verrou. Avant l'exécution de ce thread, d'autres fils doivent attendre (mais il n'est pas nécessaire de notifier la notification ici, car elle est en avis, et il est seulement nécessaire d'acquérir le verrou). Il y a le code suivant qui peut reproduire ce phénomène.
Tout d'abord, définissez une classe de threads qui peut fonctionner, comme suit:
objet final statique privé obj = nouveau objet (); La classe statique R implémente Runnable {int i; R (int i) {this.i = i; } public void run () {try {synchronisé (obj) {System.out.println ("Thread->" + i + "Waiting"); obj.wait (); System.out.println ("Thread->" + i + "Running"); Thread.Sleep (30000); }} catch (exception e) {e.printStackTrace (); }}} Faites attention à l'intérieur de la méthode de course ci-dessus. Après attendre (), nous imprimons une phrase, puis en pause le code actuel pendant 30 secondes. En ce qui concerne la méthode de sommeil, il est décrit comme suit:
Le fil ne perd pas la propriété d'aucun moniteur.
Autrement dit, la serrure est toujours maintenue.
Ensuite, définissez une méthode principale pour exécuter ces threads comme suit:
Thread [] rs = nouveau thread [10]; for (int i = 0; i <10; i ++) {rs [i] = nouveau thread (new r (i)); } pour (thread r: rs) {r.start (); } Thread.sleep (5000); synchronisé (obj) {obj.notifyall (); }Nous définissons 10 threads, puis les faisons tous. Parce qu'il y a une attente, 10 threads attendront après l'impression de "Start Run". Ensuite, la méthode principale appelle notifyall. La sortie ici apparaîtra comme suit:
Thread-> 0 en attente de thread-> 4 en attente de thread-> 5 en attente de thread-> 3 en attente de thread-> 2 en attente de thread-> 1 en attente de thread-> 6 en attente de thread-> 7 en attente de thread-> 8 en attente de thread-> 9 en attente de thread-> 9 en cours d'exécution
... Aucune autre sortie dans les 30 secondes
Dans la sortie ci-dessus, après attendre, un seul thread sort l'instruction "en cours d'exécution", et pendant une période de temps (30 secondes ici), il n'y aura pas d'autre sortie. C'est-à-dire que d'autres threads ne sortiront pas entre les verrous détenus par le code actuel.
La conclusion finale est: si le fil d'attente veut continuer à fonctionner, il doit remplir deux conditions:
L'autre thread notify ou notifyall a été notifié et le thread actuel a été informé.
Après avoir rivalisé avec d'autres fils à verrouiller, deux conditions ont été obtenues avec succès pour le verrouillage, et aucune n'a manquée. En fait, au niveau de la mise en œuvre, notifier et notifier, réaliser le même effet, et un thread continuera à s'exécuter. Mais les avis sont exemptés. La nécessité d'informer d'autres threads après l'exécution du thread, car il a été informé. Quand utiliser Notify et quand utiliser Notifyall, cela dépend de la situation réelle.
Ce qui précède est une compilation des informations pour Java Notify et Notifyall. Nous continuerons d'ajouter des informations pertinentes à l'avenir. Merci pour votre soutien pour ce site Web!