Heim  >  Artikel  >  Java  >  Java Inter-Thread-Kommunikation warten/benachrichtigen

Java Inter-Thread-Kommunikation warten/benachrichtigen

巴扎黑
巴扎黑Original
2017-06-26 11:38:571450Durchsuche

Wait/notify/notifyAll kann in Java zum Implementieren der Inter-Thread-Kommunikation verwendet werden und ist eine Methode der Object-Klasse. Diese drei Methoden sind alle native Methoden und plattformbezogen. Sie werden häufig zum Implementieren des Produzenten/ verwendet. Verbrauchermodell. Werfen wir zunächst einen Blick auf die relevanten Definitionen:

 wait(): Der Thread, der diese Methode aufruft, wechselt in den WATTING-Zustand und kehrt nur zurück, wenn er auf eine Benachrichtigung oder Unterbrechung von wartet Ein weiterer Thread-Aufruf Nach der Methode wait() wird die Sperre des Objekts aufgehoben.

Warten (lang): Warten Sie bis zu lange Millisekunden auf eine Zeitüberschreitung. Wenn keine Benachrichtigung vorliegt, erfolgt eine Zeitüberschreitung und die Rückkehr erfolgt.

Notify(): Benachrichtigen Sie einen Thread, der auf das Objekt wartet, um von der Methode wait() zurückzukehren. Die Voraussetzung für die Rückkehr ist, dass der Thread das Objekt erhält sperren.

 notifyAll(): Benachrichtigt alle Threads, die auf das Objekt warten.

Ein kleines Beispiel

Lassen Sie uns zur Veranschaulichung ein kleines Knödelrestaurant simulieren. Das Geschäft boomt und es gibt einen Koch im Laden. , ein Kellner, um zu vermeiden, dass der Kellner jedes Mal, wenn der Koch eine Portion zubereitet, eine Portion herausnimmt, was zu ineffizient ist und körperliche Energie verschwendet. Gehen Sie nun davon aus, dass der Kellner dem Kunden jedes Mal, wenn er 10 Portionen zubereitet, diese auf einem großen Holzteller serviert. Nachdem er jeden Tag 100 Portionen verkauft hat, schließt das Restaurant und der Koch und die Kellner gehen nach Hause, um sich auszuruhen.

Denken Sie darüber nach: Wenn Sie den Warte-/Benachrichtigungsmechanismus nicht verwenden, um diese Funktion zu implementieren, dann könnte der direkteste Weg darin bestehen, dass der Kellner ab und zu in die Küche geht und das herausnimmt Gerichte auf einem Teller nach 10 Portionen. Diese Methode hat zwei große Nachteile:

1. Wenn der Kellner zu fleißig in die Küche geht und der Kellner zu müde ist, ist es besser, jedes Mal, wenn eine Schüssel zubereitet wird, eine Schüssel zu servieren . Für Gäste wird die Rolle der großen Holzplatte nicht reflektiert. Die spezifische Manifestation auf der Ebene des Implementierungscodes besteht darin, dass eine kontinuierliche Schleife erforderlich ist und Prozessorressourcen verschwendet werden.

2. Wenn der Kellner nach längerer Zeit in die Küche geht, um nachzuschauen, kann die Pünktlichkeit nicht garantiert werden, aber der Koch hat bereits 10 Portionen zubereitet Kellner hat es nicht beachtet.

Für das obige Beispiel ist es viel sinnvoller, den Warte-/Benachrichtigungsmechanismus zu verwenden. Jedes Mal, wenn der Koch 10 Portionen zubereitet, ruft er „Die Knödel sind.“ Fertig, okay. Nimm es weg “. Nachdem der Kellner die Benachrichtigung erhalten hat, geht er in die Küche, um den Gästen die Knödel zu servieren. Der Koch hat noch nicht genug getan, d >aber er muss trotzdem die Ohren spitzen und auf die Benachrichtigung des Kochs warten .

 

 1 package ConcurrentTest; 2  3 import thread.BlockQueue; 4  5 /** 6  * Created by chengxiao on 2017/6/17. 7  */ 8 public class JiaoziDemo { 9     //创建个共享对象做监视器用10     private static Object obj = new Object();11     //大木盘子,一盘最多可盛10份饺子,厨师做满10份,服务员就可以端出去了。12     private static Integer platter = 0;13     //卖出的饺子总量,卖够100份就打烊收工14     private static Integer count = 0;15 16     /**17      * 厨师18      */19     static class Cook implements Runnable{20         @Override21         public void run() {22             while(count<100){23                 synchronized (obj){24                     while (platter<10){25                         platter++;26                     }27                     //通知服务员饺子好了,可以端走了28                     obj.notify();29                     System.out.println(Thread.currentThread().getName()+"--饺子好啦,厨师休息会儿");30                 }31                 try {32                     //线程睡一会,帮助服务员线程抢到对象锁33                     Thread.sleep(100);34                 } catch (InterruptedException e) {35                     e.printStackTrace();36                 }37             }38             System.out.println(Thread.currentThread().getName()+"--打烊收工,厨师回家");39         }40     }41 42     /**43      * 服务员44      */45     static class Waiter implements Runnable{46         @Override47         public void run() {48             while(count<100){49                 synchronized (obj){50                     //厨师做够10份了,就可以端出去了51                     while(platter < 10){52                         try {53                             System.out.println(Thread.currentThread().getName()+"--饺子还没好,等待厨师通知...");54                             obj.wait();55                             BlockQueue56                         } catch (InterruptedException e) {57                             e.printStackTrace();58                         }59                     }60                     //饺子端给客人了,盘子清空61                     platter-=10;62                     //又卖出去10份。63                     count+=10;64                     System.out.println(Thread.currentThread().getName()+"--服务员把饺子端给客人了");65                 }66             }67             System.out.println(Thread.currentThread().getName()+"--打烊收工,服务员回家");68 69         }70     }71     public static void main(String []args){72         Thread cookThread = new Thread(new Cook(),"cookThread");73         Thread waiterThread = new Thread(new Waiter(),"waiterThread");74         cookThread.start();75         waiterThread.start();76     }77 }
Ein kleines Beispiel
Laufergebnis

cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--饺子还没好,等待厨师通知...
cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--饺子还没好,等待厨师通知...
cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--饺子还没好,等待厨师通知...
cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--饺子还没好,等待厨师通知...
cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--饺子还没好,等待厨师通知...
cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--饺子还没好,等待厨师通知...
cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--饺子还没好,等待厨师通知...
cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--饺子还没好,等待厨师通知...
cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--饺子还没好,等待厨师通知...
cookThread--饺子好啦,厨师休息会儿
waiterThread--服务员把饺子端给客人了
waiterThread--打烊收工,服务员回家
cookThread--打烊收工,厨师回家
Laufergebnisse

Betriebsmechanismus

Leihen Sie sich ein Bild aus „The Art of Concurrent Programming“ aus, um den Betriebsmechanismus von Warten/Benachrichtigen zu verstehen

Vielleicht kennt mich jemand Ich weiß nicht viel über den sogenannten Monitor (Monitor) und die Objektsperre (Sperre). Hier ist eine einfache Erklärung:

  JVM ordnet jedem Objekt eine Sperre zu Das Sperren eines Objekts bedeutet, dass der mit dem Objekt verknüpfte Monitor abgerufen wird.

Nur wenn die Objektsperre fehlschlägt, wird der Thread in die Blockierungswarteschlange aufgenommen Erfolgreich Nachdem Sie die Objektsperre erhalten haben, können Sie auch die Methode wait () verwenden, um auf dem Monitor zu warten. Zu diesem Zeitpunkt wird die Sperre aufgehoben und in die Warteschlange eingetragen.

Zum Unterschied zwischen Schlössern und Monitoren habe ich hier einen sehr ausführlichen und ausführlichen Artikel für Interessierte geschrieben Schauen Sie sich Der Unterschied zwischen Sperren und Monitoren – Java-Parallelität

Lassen Sie uns anhand der obigen Abbildung den spezifischen Prozess klären

1. Zuerst erwirbt waitThread die Objektsperre und ruft dann die Methode wait() auf. Zu diesem Zeitpunkt gibt der Wartethread die Objektsperre auf und gibt die Wartewarteschlange WaitQueue中;

2. Der notifyThread-Thread übernimmt die Objektsperre, führt einige Vorgänge aus und ruft die notify()-Methode auf. Zu diesem Zeitpunkt ist der Wartethread waitThread wird aus der Warteschlange WaitQueue in die Synchronisierungswarteschlange verschoben. In der Warteschlange SynchronizedQueue wechselt waitThread vom Wartezustand in den blockierten Zustand. Es ist zu beachten, dass notifyThread die Sperre zu diesem Zeitpunkt nicht sofort aufhebtEs wird weiter ausgeführt und die Sperre erst freigegeben, nachdem der Rest seiner Arbeit abgeschlossen ist;

3. waitThread erhält die Objektsperre erneut, kehrt von der Methode wait() zurück und führt nachfolgende Vorgänge weiter aus

4. Der Prozess der Kommunikation zwischen Threads basiert auf dem Der Warte-/Benachrichtigungsmechanismus endet.

Wie bei notifyAll werden im zweiten Schritt alle Threads in der

Wartewarteschlange in die Synchronisationswarteschlange verschoben.

Fallstricke vermeiden

Bei der Verwendung von wait/notify/notifyAll sind einige Besonderheiten zu beachten:

1 wait()/notify()/notifyAll() ist synchronisiert, was bedeutet, dass Sie zuerst die Sperre erwerben müssen. Wir haben dies bereits erwähnt, da der Monitor erst nach dem Sperren erhalten werden kann. Andernfalls löst JVM auch eine IllegalMonitorStateException aus.

2. Bei Verwendung von wait() muss die Bedingung, um zu bestimmen, ob der Thread in den Wartezustand wechselt, while anstelle von if verwenden, da der wartende Thread möglicherweise vorhanden ist Um die Sicherheit zu gewährleisten, sollten Sie daher vor und nach dem Warten mithilfe einer While-Schleife prüfen, ob die Aufwachbedingungen erfüllt sind.

3. Nachdem die Methode notify() oder notifyAll() aufgerufen wurde, gibt der Thread die Sperre nicht sofort frei. Der Aufruf verschiebt nur den wartenden Thread aus der Warteschlange in die Synchronisationswarteschlange, d. Von wait() Die Voraussetzung für die Rückkehr der Methode ist, dass der Thread die Sperre des aufrufenden Objekts wiedererlangt.

Postscript

 Dies ist die Einführung von Warte-/Benachrichtigungsinhalten. Bei der tatsächlichen Verwendung sollte besonderes Augenmerk auf das oben genannte A gelegt werden Einige Punkte, aber im Allgemeinen verwenden wir wait/notify/notifyAll direkt, um die Kommunikation zwischen Threads abzuschließen. Es gibt nicht viele Möglichkeiten für das Producer/Consumer-Modell, da das Java-Parallelitätspaket viele hervorragende und exquisite Tools bereitgestellt hat, wie z BlockingQueue usw. werden später bei Gelegenheit ausführlich vorgestellt.

Sich gegenseitig ermutigen

Das obige ist der detaillierte Inhalt vonJava Inter-Thread-Kommunikation warten/benachrichtigen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:Java-MindmapNächster Artikel:Java-Mindmap