La fonction de la condition est de fournir un contrôle plus précis du verrou. La méthode Await () en condition est équivalente à la méthode d'objet Wait (), la méthode Signal () en condition est équivalente à la méthode Notify () de l'objet, et le Signalall () en condition est équivalent à la méthode NotifyAll () de l'objet. La différence est que les méthodes attend (), notify () et notifyall () dans l'objet sont regroupées avec "verrouillage synchronisé" (mot-clé synchronisé); et l'état doit être regroupé avec "mutex" / "partager le verrouillage".
Liste des fonctions de condition
// fait attendre le thread actuel jusqu'à ce qu'il reçoive un signal ou qu'il soit interrompu. void wait () // fait rester le thread actuel dans un état d'attente avant de recevoir un signal, d'être interrompu ou d'atteindre le temps d'attente spécifié. Boolean Await (longue durée, unité TimeUnit) // entraîne le thread actuel dans un état d'attente jusqu'à ce qu'il reçoive un signal, est interrompu ou atteint le temps d'attente spécifié. Long Awaitnanos (Long Nanostimeout) // fait que le thread actuel est dans un état d'attente avant de recevoir le signal. VOID AWAITUNTERURUBLIBLEMENT () // fait rester le thread actuel dans un état d'attente jusqu'à ce qu'il reçoive un signal, est interrompu ou atteint la date limite spécifiée. Boolean Awaituntil (date limite de date) // Réveille un fil d'attente. void signal () // réveiller tous les threads en attente. void signalall ()
Exemple d'utilisation de la classe Condition
La condition décompose les méthodes de moniteur d'objets (attendez, notifiez et notifiez) en objets complètement différents afin qu'en combinant ces objets avec n'importe quelle implémentation de verrouillage, chaque objet fournit plusieurs ensembles d'attente (ensemble d'attente). Parmi eux, Lock remplace l'utilisation des méthodes et des instructions synchronisées et la condition remplace l'utilisation des méthodes de moniteur d'objet. Ce qui suit est un exemple précédemment écrit de communication de thread avec l'implémentation avec la condition, le code est le suivant:
classe publique threadTest2 {public static void main (string [] args) {final business business = new business (); Nouveau thread (new Runnable () {@Override public void run () {ThreadExecute (Business, "sub");}}). start (); ThreadExecute (Business, "Main"); } public static void threadExecute (Business Business, String ThreadType) {for (int i = 0; i <100; i ++) {try {if ("main" .equals (threadType)) {business.main (i); } else {business.sub (i); }} catch (InterruptedException e) {e.printStackTrace (); }}}} classe Business {private boolean bool = true; Lock de verrouillage privé = new reentrantLock (); condition de condition privée = lock.newCondition (); public / * synchronisé * / void main (int boucle) lance InterruptedException {lock.lock (); essayez {while (bool) {condition.await (); // this.wait (); } pour (int i = 0; i <100; i ++) {System.out.println ("Thread principal seq de" + i + ", boucle de" + boucle); } bool = true; condition.signal (); // this.notify (); } enfin {lock.unlock (); }} public / * synchronisé * / void sub (int lOop) lance InterruptedException {lock.lock (); essayez {while (! bool) {condition.await (); // this.wait (); } pour (int i = 0; i <10; i ++) {System.out.println ("Sub Thread Seq de" + i + ", boucle de" + boucle); } bool = false; condition.signal (); // this.notify (); } enfin {lock.unlock (); }}} En condition, remplacez Wait () par Await (), remplacez Notify () par Signal () et remplacez NotifyAll () par Signalall (). La méthode de communication traditionnelle des threads peut être mise en œuvre. Notez ici que la condition est liée à une serrure. Pour créer un verrou, vous devez utiliser la méthode NewCondition ().
De cette façon, l'état n'est pas différent de la communication traditionnelle du fil. La puissance de la condition est qu'elle peut établir différentes conditions entre plusieurs threads. Ce qui suit est un morceau de code de l'API pour illustrer.
Class BoundedBuffer {Final Lock Lock = new RentrantLock (); // Lock Object Final Condition Notull = Lock.NewCondition (); // Écriture de la condition de thread Final Condition Nothempty = Lock.NewCondition (); // Lire Thread Condition Object Final Object [100]; 100]; // Cached Quoute file d'attente*/; public void put (objet x) lève InterruptedException {lock.lock (); essayez {while (count == items.length) // si la file d'attente est pleine de notull.await (); // bloquez les éléments du thread d'écriture [putptr] = x; // affecter if (++ putptr == items.length) putptr = 0; // si l'index d'écriture est écrit à la dernière position de la file d'attente, définissez-le à 0 ++. thread} enfin {lock.unlock (); }} public Object Take () lance InterruptedException {lock.lock (); essayez {while (count == 0) // si la file d'attente est vide notEmpty.Await (); // bloquez l'objet de thread de lecture x = éléments [TakePtr]; // Choisissez la valeur if (++ TakePtr == Items.Length) TakePtr = 0; } enfin {lock.unlock (); }}} Il s'agit d'une zone de cache dans un environnement de travail multi-thread. La zone de cache fournit deux méthodes: mettre et prendre. PUT est pour stocker des données, prendre pour récupérer des données, et il y a une file d'attente de cache à l'intérieur. Voir le code pour des variables et des descriptions de méthodes spécifiques. Les fonctions implémentées par cette classe de zone de cache: plusieurs threads stockent des données et récupérez des données à partir de celles-ci. La valeur de cache maximale que la file d'attente de cache (d'abord dans, d'abord dehors, puis dans, puis à sortir) peut être cache est de 100. Plusieurs threads s'excluent mutuellement. Lorsque la valeur stockée dans la file d'attente de cache atteint 100, le fil d'écriture sera bloqué et le thread de lecture sera éveillé. Lorsque la valeur stockée dans la file d'attente de cache est 0, le thread de lecture sera bloqué et le thread d'écriture sera éveillé. L'analyse suivante du processus d'exécution du code:
1. Un thread d'écriture exécute et appelle la méthode de put;
2. Pour déterminer si le nombre est de 100, il n'y a évidemment pas 100;
3. Continuez à exécuter et à déposer la valeur;
4. Après avoir déterminé la position d'index actuellement écrite ++, si elle est égale à 100. Égaliser la valeur d'index d'écriture à 0 et compter + 1;
5. Réveillez-vous seulement une des files d'attente de blocage du fil de lecture;
6. Exécutez un thread de lecture et appelez la méthode Take;
7.…
8. Réveillez-vous seulement une des files d'attente des fils d'écriture.
C'est la puissance de plusieurs conditions. En supposant que la file d'attente de cache est pleine, alors le blocage est définitivement le fil d'écriture, et le réveil est définitivement le fil de lecture. Au contraire, le blocage est définitivement le fil de lecture, et le réveil est définitivement le fil d'écriture. Alors, que se passera-t-il s'il n'y a qu'une seule condition? La file d'attente de cache est pleine, ce verrou ne sait pas s'il s'agit du thread de lecture ou du fil d'écriture. Si le réveil est le fil de lecture, tout le monde est heureux. Si le réveil est le fil d'écriture, le fil vient d'être éveillé et bloqué à nouveau, puis se réveille à nouveau, ce qui perd beaucoup de temps.