Das Verbrauchermuster des Herstellers ist das häufigste Muster unter Multi-Threading: Der Produzentfaden (ein oder mehrere) erzeugt Brot und stellt es in den Korb (eingestellt oder Array), und gleichzeitig nimmt der Verbraucher-Thread (ein oder mehrere) das Brot aus dem Korb (Set oder Array) und verbraucht es. Obwohl sie unterschiedliche Aufgaben haben, sind die Ressourcen, die sie verarbeiten, gleich, was eine Methode der Kommunikation zwischen den Threads widerspiegelt.
In diesem Artikel wird zunächst die Situation einzelner Produzenten und einzelner Verbraucher erläutert und dann die Situation des Multi-Produzenten- und Multi-Consumer-Modells erklären. Diese beiden Modi werden auch mit dem Mechanismus wait ()/nofity ()/nofityAll () und dem Mechanismus lock ()/unlock () implementiert.
Erklären Sie vor Beginn der Einführung des Musters die Verwendungsdetails der Methoden Wait (), Notify () und Notifyall () sowie die verbesserte Verwendung von lock ()/unlock (), warten Sie ()/signal ()/signalall ().
1. Das Prinzip des Wartens und Weckmechanismus
Warten Sie (), benachrichtigen () bzw. notifyall () stellen Threads dar, die in den Schlaf eintreten, den Schlaffaden aufwecken und alle Schlaffäden aufwecken. Aber welcher Thread ist das Objekt? Darüber hinaus müssen alle drei in der API -Dokumentation beschriebenen Methoden unter der Prämisse eines gültigen Monitors verwendet werden (der als Halten eines Schlosses verstanden werden kann). Was haben diese drei Methoden mit dem Sperren zu tun?
Die Synchronisationscode -Block -Synchronisierungsfunktionen (OBJ) {} oder Synchronisationsfunktionen als Beispiel: Wait (), Notify () und NotifyAll () können in ihrer Codestruktur verwendet werden, da sie alle Sperren halten.
Für die folgenden zwei Synchronisationscodeblöcke werden Lock OBJ1 und Lock OBJ2 jeweils verwendet. Thread 1 und Thread 2 Führen Sie den Synchronisierungscode aus, der dem OBJ1 entspricht, und Thread 3 und Thread 4 führen den Synchronisationscode aus, der dem OBJ2 entspricht.
Klasse mylock implementiert runnable {public int flag = 0; Objekt obj1 = neues Objekt (); Objekt obj2 = neues Objekt (); public void run () {while (true) {if (flag%2 = 0) {synchronized (obj1) {// threads t1 und t2 Führen Sie diese Synchronisierungsaufgabe durch // try {obj1.wait ();} catch (intercustedExceda synchronisiert (obj2) {// Thread T3 und T4 Führen Sie diese Synchronisierungsaufgabe durch // try {obj2.wait ();} catch (interruptedException i) {} //obj2.notify () //obj2.notifyall ()}}}}}}}}}}}}}}}} {my my}} {}} {my my} {}}} {public {{{{static static main (static Main = neuer mylock (); Thread T1 = neuer Thread (ML); Thread T2 = neuer Thread (ML); Thread T3 = neuer Thread (ml); Thread T4 = neuer Thread (ML); t1.start (); t2.Start (); try {thread.sleep (1)} catch (InterruptedException i) {}; ml.flag ++; t3.Start (); t4.Start (); }}Wenn T1 auf das Warten () ausgeführt wird, tritt es in einen Schlafzustand ein, ist jedoch kein normaler Schlaf, sondern schläft in einem von OBJ1 identifizierten Fadenpool (tatsächlich entspricht der Monitor dem Fadenpool, aber der Monitor und die Sperre sind zu diesem Zeitpunkt zusammengebunden). Wenn T2 ausgeführt wird, wird festgestellt, dass das Sperren OBJ1 von anderen Threads gehalten wird und in einen Schlafzustand eintritt. Diesmal liegt es daran, dass die Schlossressource eher wartet als der von Wait () eingegebene Schlaf. Da T2 bereits festgestellt hat, dass es sich um das OBJ1 -Schloss beantragt, tritt er auch in den Schlaf im OBJ1 -Thread -Pool an und nicht den normalen Schlaf. In ähnlicher Weise betreten diese beiden Threads T3 und T4 in den Schlaf -Thread -Pool zum Schlafen.
Wenn ein Thread auf benachrichtigt () ausführt, weckt dieser Benachrichtigung () einen Thread im Thread -Pool zufällig auf, der seiner Sperre entspricht. Zum Beispiel weckt obj1.notify () einen schlafenden Faden im OBJ1 -Thread -Pool (natürlich, wenn es keinen schlafenden Faden gibt, dann nichts tun). In ähnlicher Weise weckt Notifyall () alle Schlaffäden im entsprechenden Gewindepool des Schlosses auf.
Was Sie herausfinden müssen, ist das "entsprechende Schloss", da das Schloss explizit angegeben werden muss, wenn Sie Wait (), benachrichtigen () und notifyAll () aufrufen. Zum Beispiel obj1.wait (). Wenn das Schloss dazu gehört, weggelassen, bedeutet dies, dass dieses Objekt, dh die Präfixe dieser drei Methoden, nur in nicht statischen Synchronisationsfunktionen weggelassen werden können.
Kurz gesagt, wenn die Synchronisation verwendet wird, wird das Schloss verwendet und der Faden hat ein Zuhause, und ihre gesamte Grundlage wird durch das Zugehörigkeitsschloss bestimmt. Bei der Threadsynchronisation bestimmt beispielsweise, ob die Sperre nicht im Leerlauf entscheidet, ob der nachfolgende Code ausgeführt werden soll, und auch festzustellen, ob in einen bestimmten Thread -Pool zum Schlaf gehen soll. Beim Erwachen weckt es nur den Faden im Fadenpool, der dem Schloss entspricht.
Bei der Anwendung dieser Methoden erscheinen im Allgemeinen in einer Aufgabe Warten () und notify ()/notifyAll () paarweise und führen Sie einzeln aus. Mit anderen Worten, während dieser Runde der atomaren synchronen Ausführung wird entweder Wait () in den Schlaf ausgeführt oder benachrichtigt (), um den Schlaf -Thread im Thread -Pool aufzuwecken. Um eine selektive Ausführung zu erreichen, können Sie die Markierung als Grundlage für das Urteilsvermögen in Betracht ziehen. Siehe folgende Beispiele.
2. Schließen und Zustand
Die drei Methoden der Wait () -Serie sind sehr begrenzt, da sowohl Schlaf- als auch Weckaktionen vollständig mit dem Schloss verbunden sind. Zum Beispiel kann der mit dem Sperre zugefügte Faden OBJ1 den Faden nur im OBJ1 -Thread -Pool aufwecken, aber den mit dem Sperren OBJ2 zugeordneten Faden nicht aufwecken. Wenn beispielsweise die synchronisierte Synchronisation ursprünglich synchronisiert wurde, wurde die Sperre implizit automatisch erfasst, als die Synchronisation begann, und nachdem die gesamte Aufgabe ausgeführt worden war, wurde das Schloss implizit automatisch freigesetzt, was bedeutet, dass die Wirkung des Schlosses und die Freigabe des Schlosses nicht manuell kontrolliert werden konnte.
Ab JDK 1.5 stellt Java das Paket von Java.util.Concurrent.locks bereit, das die Schnittstelle für Sperre, Bedingung und ReadWriteLock -Schnittstelle bietet. Die ersten beiden Schnittstellen entkoppeln die Verriegelungs- und Monitormethoden (Schlaf, Weckvorgänge). Die Sperroberfläche enthält nur Schlösser. Durch die Lock -Methode können Newconditon () ein oder mehrere Monitore des Schlosses erzeugt werden. Jeder Monitor verfügt über eigene Schlaf- und Weckmethoden. Mit anderen Worten, die Sperre ersetzt die Verwendung synchronisierter Methoden und synchronisierten Codeblöcke und der Zustand ersetzt die Verwendung von Objektmonitormethoden.
Wie in der Abbildung unten gezeigt:
Wenn ein Thread Condition1.Await () ausführt, tritt der Thread den Thread -Pool ein, der dem Bedingungsmonitor für den Schlaf entspricht. Wenn Condition1.Signal () ausgeführt wird, wird jeder Thread im Bedingungs -Thread -Pool zufällig erweckt. Wenn Condition1.Signalall () ausgeführt wird, werden alle Threads im Bedingung1 -Thread -Pool geweckt. In ähnlicher Weise gilt dies auch für den Condition2 -Monitor.
Selbst wenn mehrere Monitore vorhanden sind, kann der andere Thread über den Monitor betrieben werden, solange sie demselben Sperrobjekt zugeordnet sind. Beispielsweise kann ein Thread in Condition1 Condition2.Signal () ausführen, um einen Thread im Zustand2 -Thread -Pool aufzuwecken.
Um diese Art der Assoziation von Schlössern und Monitoren zu verwenden, lesen Sie die folgenden Schritte:
Import Java.util.Concurrent // Da das Code -Segment abnormal sein kann, muss entsperr () ausgeführt werden. Versuchen Sie zu verwenden, und entsperr () muss in das endgültige Segment eingefügt werden}
Für eine spezifische Verwendung finden Sie im späteren Beispielcode für Sperren und Zustand.
3. Einzelproduzent Einzelverbrauchermodell
Ein Produzentfaden, ein Verbraucher -Thread. Für jedes vom Hersteller erzeugte Brot nimmt der Verbraucher das Brot zum Verbrauch aus dem Teller. Die Grundlage für die Produzenten zu beurteilen, ob die Produktion fortgesetzt werden soll, besteht darin, dass kein Brot auf dem Teller vorhanden ist, während die Grundlage für Verbraucher beurteilen, ob sie konsumiert werden sollen, ist, dass sich Brot auf dem Teller befindet. Da in diesem Modus immer nur ein Brotbrot auf den Teller gelegt wird, kann der Teller weggelassen werden und der Hersteller und der Verbraucher können die Brot schrittweise übergeben.
Zunächst müssen wir diese drei Kategorien beschreiben: Eine ist die Ressource, die von mehreren Threads betrieben wird (hier ist Brot), der zweite der Produzent und der dritte der Verbraucher. Im folgenden Beispiel verkapsle ich die Methoden zur Herstellung von Brot und zum Konsumieren von Brot in den Hersteller- und Verbraucherklassen, was leichter zu verstehen ist, wenn sie in der Brotklasse eingekapselt werden.
// Beschreibung Ressource: Der Name und die Anzahl der Brot, bestimmt durch die Anzahl der Brotklassenbrot {public String Name; public int count = 1; öffentliche Boolesche Flagge = Falsch; // Diese Marke liefert Urteilsmarken für Wait () und benachrichtigen ()} // Die vom Hersteller und dem Verbraucher verarbeitete Brotressource sind gleich. Um dies zu gewährleisten, kann // die Brotklasse nach dem Singleton -Muster entworfen werden, oder das gleiche Brotobjekt kann durch die Konstruktionsmethode an den Hersteller und den Verbraucher übergeben werden. Die letztere Methode wird hier verwendet. // Beschreiben Sie den Produzenten -Produzenten implementiert Runnable {Private Bread b; // Mitglied des Produzenten: Die Ressource, die es produzieren möchte (Brot B) {this.b = b; } // Bereitstellung einer Methode zur Herstellung von Brotpublikum void produzieren (String -Name) {B.Name = Name + B.Count; B.Count ++; } public void run(){ while(true){ synchronized(Bread.class){ //Use Bread.class as the lock identifier so that the synchronized code blocks of producers and consumers can use the same lock if(b.flag){ //wait() must be inside the synchronous code block, not only because the lock must be held to sleep, but there will be confusion in the judgment of the lock resource try {bread.class.wait ();} catch (InterruptedException i) {}} produzieren ("Bread"); System.out.println(Thread.currentThread().getName()+"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // Notify () muss auch synchronisiert werden, ansonsten wurde das Schloss veröffentlicht, und die Weckaktion kann nicht durchgeführt werden // PS: In einer Synchronisationsaufgabe () sollte nur ausgeführt werden, da der andere Partei-Thread verwirrt ist. this.b = b; System.out.println (Thread.CurrentThread (). GetName ()+"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------/ // 2.Das endgültige Ausführungsergebnis sollte erzeugt und konsumiert werden, und dies ist ein kontinuierlicher Zyklus. wie folgt:
Thread-0 --- Produzent ---- Bread1Thread-1 --- Verbraucher ------- Bread1Thread-0 --- Produzent ---- Bread2Thread-1 ------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4. Verwenden Sie Schloss und Zustand, um einzelne Produktions- und Verbrauchsmodell zu realisieren
Der Code ist wie folgt:
importieren java.util.concurrent.locks.*; Class Bread {public String name; public int count = 1; öffentliche Boolesche Flagge = Falsch; // Das gleiche Lock -Objekt und das gleiche Bedingungsobjekt für Produzenten und Verbraucher öffentliche statische Lock Lock = New Reentrantlock () angeben; öffentliche statische Bedingung Zustand = lock.newcondition ();} Klassenproduzent implementiert Runnable {privates Brot b; Produzent (Brot B) {this.b = b; } public void Produc (String -Name) {B.Name = Name + B.Count; B.Count ++; } public void run () {while (true) {// Verwenden Sie Bread.lock, um das Ressourcenbrot zu sperren.lock.lock (); try {if (b.flag) {try {bread.condition.await ();} catch (interruptedException i) {}} produzieren ("bread"); System.out.println (Thread.CurrentThread (). GetName ()+"---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Bread.Condition.Signal (); try {if (! b.flag) {try {bread.condition.await ();} catch (InterruptedException i) {}} System.out.println (Thread.CurrentThread (). GetName ()+"---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // 2.5. Mehrproduktions- und Verbrauchsmodell (Einzelbrot)
Hier erklären wir zunächst das Modell mehrerer Hersteller und mehrerer Verbraucher, aber höchstens gleichzeitig Brot. Dieses Modell ist in der Realität möglicherweise nicht ideal, aber um später zu dem realen Mehrproduktions- und Mehrfachverbrauchsmodell zu führen, ist es meiner Meinung nach erforderlich, dieses Modell hier zu erklären und dieses Modell zu analysieren und wie es sich aus dem Einzelproduktions- und Einzelverbrauchscode entwickelt hat.
Wie in der Abbildung unten gezeigt:
Von einer einzelnen Produktion und einem einzelnen Verbrauch bis hin zu mehreren Produktion und mehreren Verbrauch aufgrund von Sicherheitsproblemen mit Multi-Thread und Deadlock-Problemen müssen zwei Probleme berücksichtigt werden:
Wie kann Multi-Threading für eine Partei die gleiche Produktions- oder Verbrauchskapazität wie ein Threading erreichen? Mit anderen Worten, wie man Multi-Threading-Einzel-Threading aussieht. Der größte Unterschied zwischen Multi-Threading und Single-Threading ist die Sicherheit von Multi-Threading. Solange Sie sicherstellen, dass die durch Multi-Threading ausgeführten Aufgaben synchronisiert werden können.
Die erste Frage berücksichtigt das Problem des Multi-Threading auf einer Partei, und in der zweiten Frage wird berücksichtigt, wie die beiden Parteien harmonisch zusammenarbeiten können, um die Produktion und den Verbrauch zu vervollständigen. Das heißt, wie man sicherstellt, dass eine Seite des Herstellers und des Verbrauchers schläft, während die andere Seite aktiv ist. Wach einfach die andere Partei auf, wenn eine Partei die Synchronisierungsaufgabe erledigt hat.
In der Tat müssen zwei Probleme in Betracht gezogen werden: Out-of-Synchronization und Deadlock. (1) Wenn sowohl der Produzent als auch die Verbraucherseite Multi-Threads haben, können die Multi-Threads des Herstellers als Ganzes als Faden angesehen werden, und die Multi-Threads der Verbraucherseite auch als Ganzes, was das Problem der Fadensicherheit löst. (2) Die Kombination der gesamten Produktion und des gesamten Verbrauchers wird als Multi-Threading angesehen, um das Deadlock-Problem zu lösen. Der Weg zur Lösung der Deadlock in Java besteht darin, die andere Partei aufzuwecken oder alles aufzuwachen.
Die Frage ist, wie Sie die Synchronisation zwischen mehreren Threads einer bestimmten Partei sicherstellen können. Der Code eines einzelnen Verbrauchers wird als Beispiel durch Multi-Thread-Ausführung analysiert.
while (true) {synchronized (bread.class) {if (! b.flag) {try {bread.class.wait ();} catch (interruptedException i) {}} System.out.println (Thread.CurrentThread (). GetName ()+"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Nehmen wir an, dass der Konsumfaden 1 den Verbrauch Thread 2 aufweckt, nachdem ein Laib Brot konsumiert wurde, und weiterhin schaufelt, beurteilen Sie, ob (! Flag) wartet, und das Schloss wird freigegeben. Unter der Annahme, dass die CPU nur ein Verbraucher -Thread 2 auswählt, wird das Verbraucher -Thread 2 auch das Warten eingeben. Wenn der Produzent ein Brot -Laib produziert, nehmen Sie an, dass der Konsumfaden 1 erweckt wird, er wird weiterhin das neu produzierte Brot aus der Wartenaussage verbrauchen, nehmen Sie an, dass der Konsumfaden 2 erneut geweckt wird. Wenn der Konsumfaden 2 von der CPU ausgewählt wird, wird der Konsum -Thread 2 auch aus der Wartenaussage nach unten konsumiert, und das gerade erzeugte Brot wird verbraucht. Das Problem tritt wieder auf. Kontinuierlich erweckte Verbrauchsfäden 1 und 2 konsumieren das gleiche Brot, was bedeutet, dass das Brot wiederholt konsumiert wird. Dies ist ein weiteres Multi-Thread-Out-Sync-Problem.
Nachdem es lange darüber gesprochen hat, ist es tatsächlich sehr einfach zu analysieren, nachdem es die Sichtlinie vergrößert hat. Solange die zwei oder mehr Fäden einer Partei auf das Urteil b.flag warten, können die zwei oder mehr Fäden kontinuierlich geweckt werden und weiterhin nach unten produziert oder verbraucht werden. Dies schafft das Problem der Multi-Threading-Outsynchronisierung.
Das Problem der Unsicherheit liegt in der Tatsache, dass mehrere Fäden auf derselben Partei nach kontinuierlichem Erwachen weiterhin nach unten produzieren oder nach unten konsumieren. Dies wird durch die IF -Aussage verursacht. Wenn der Wait -Thread zurückdrehen kann, um festzustellen, ob B.Flag nach dem Aufwachen wahr ist, kann er entscheiden, ob Sie weiter warten oder produzieren oder nach unten konsumiert werden sollen.
Sie können die IF -Erklärung durch eine Weile ersetzen, um die Anforderungen zu erfüllen. Auf diese Weise werden sie unabhängig davon, ob mehrere Fäden auf einer bestimmten Partei kontinuierlich erweckt werden, zurück zu Richter B.Flag.
while (true) {synchronized (bread.class) {while (! b.flag) {try {bread.class.wait ();} catch (interruptedException i) {}} System.out.println (Thread.CurrentThread (). GetName ()+"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Das erste Multithread -Sicherheitsproblem wurde gelöst, aber Deadlock -Probleme traten auf. Dies ist leicht zu analysieren. Der Produzent gilt als Ganzes und der Verbraucher ist ebenfalls ein Ganzes. Wenn die Fäden des Produzenten alle warten (die Fäden der Produktionspartei werden kontinuierlich geweckt, alle Fäden der Party werden warten), und der Verbraucher wartet ebenfalls und der Deadlock wird erscheinen. Wenn Sie es auf verstärkte Weise betrachten, werden Produzent und Verbraucher als ein Thread angesehen. Diese beiden Threads bilden mehrere Threads. Wenn eine Seite wartet und die andere Seite nicht wecken kann, wird die andere Seite auf jeden Fall warten, sodass sie abgestimmt wird.
Für das Problem der Deadlock zwischen beiden Parteien kann es gelöst werden, solange Sie sicherstellen, dass die andere Partei geweckt werden kann, und nicht das kontinuierliche Erwachen einer Partei. Verwenden Sie einfach notifyAll () oder signalAll (), oder Sie können den anderen Faden über Signal () aufwachen, um das Problem zu lösen. Siehe den zweiten Code unten.
Laut der obigen Analyse kann der Code für einzelne Produktion und Einzelverbrauchsmodell in ein Einzelbrotmodell mit mehreren Produkten und einem Mehrkonsummodell geändert werden.
// Code -Segment 1 Class Bread {public String Name; public int count = 1; öffentliche Boolesche Flagge = Falsch; } // Beschreiben Sie den Produzenten der Produzenten -Produzenten implementiert Runnable {private Bread b; Produzent (Brot B) {this.b = b; } public void Produc (String -Name) {B.Name = Name + B.Count; B.Count ++; } public void run () {while (true) {synchronized (bread.class) {while (b.flag) {try {bread.class.wait ();} catch (interruptedException i) {}} produzieren ("Bread"); System.out.println (Thread.CurrentThread (). GetName ()+"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- String Consumpt () {return b.name;} public void run () {while (true) {synchronized (bread.class) {while (! B.Flag) {try {bread.class.wait ();} catch (interruptedException i) {}} System.out.println (Thread.CurrentThread (). GetName ()+"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ }} öffentliche Klasse produzieren 2 Thread con_t1 = neuer Thread (con);Das Folgende ist der Code, der unter Verwendung von Signal () mit Lock und Conditon umgestaltet wurde, um den anderen Thread aufzuwecken.
// Code -Segment 2Import java.util.concurrent.locks.*; public int count = 1; öffentliche Boolesche Flagge = Falsch; öffentliches statisches Lock Lock = New Reentrantlock (); öffentliche statische Bedingung pro_con = lock.newcondition (); public static condition con_con = lock.newCondition ();} // Beschreiben Sie den Produzenten der Produzentenklasse implementiert Runnable {private Bread b; Produzent (Brot B) {this.b = b; } public void Produc (String -Name) {B.Name = Name + B.Count; B.Count ++; } public void run () {while (true) {bread.lock.lock (); try {while (b.flag) {try {bread.pro_con.await ();} catch (interruptedException i) {}} produzieren ("bread"); System.out.println(Thread.currentThread().getName()+"----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Bread.con_con.signal (); Bread.lock.lock (); System.out.println (Thread.CurrentThread (). GetName ()+"---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //2. Create producer and consumer objects Producer pro = new Producer(b); Consumer con = new Consumer(b); //3. Create thread object Thread pro_t1 = new Thread(pro); Thread pro_t2 = new Thread(pro); Thread con_t1 = new Thread(con); Thread con_t2 = new Thread(con); pro_t1.start(); pro_t2.start(); con_t1.start(); con_t2.Start ();Fassen wir die Probleme der Produktion und des mehr Verbrauchs zusammen:
(1). Die Lösung für die Multi-Threading-Synchronisation einer bestimmten Partei besteht darin, während des Wartens zu bestimmen, ob das Warten;
(2). Die Lösung für das Deadlock -Problem beider Parteien besteht darin, die andere Partei aufzuwecken. Sie können notifyAll (), signalAll () oder die Signal () -Methode des Monitors der anderen Partei verwenden.
6. Mehr Produktions- und Verbrauchsmodelle
Es gibt mehrere Produzenten -Threads und mehrere Verbraucherfäden. Der Produzent steckt das produzierte Brot in einen Korb (Set oder Array), und der Verbraucher nimmt das Brot aus dem Korb. Die Grundlage für die Produzenten, die die Produktion fortsetzen zu können, besteht darin, dass der Korb voll ist und die Grundlage für Verbraucher, den fortgesetzten Verbrauch zu beurteilen, ob der Korb leer ist. Wenn der Verbraucher das Brot herausnimmt, wird die entsprechende Position wieder leer, und der Produzent kann die Produktion von der Startposition des Korbs umkehren und fortsetzen, die durch Zurücksetzen des Zeigers des Korbs erreicht werden kann.
In diesem Modell ist es zusätzlich zur Beschreibung von Produzenten, Verbrauchern und Brot auch notwendig, den Korbbehälter zu beschreiben. Angenommen, ein Array wird als Container verwendet, jedes Mal, wenn der Produzent einen produziert, verschiebt sich der Produktionszeiger nach hinten, und jedes Mal, wenn der Verbraucher einen konsumiert, verschiebt sich der Verbrauchzeiger nach hinten.
Der Code lautet wie folgt: Sie können sich auf den in der API angegebenen Beispielcode beziehen-> Bedingungsklasse
import Java.util.concurrent.locks.*; Klassenkorb {private Bread [] arr; // die Größe des Korbkorbs (int Größe) {arr = neues Brot [Größe]; } // Der Zeiger von in und out private int in_ptr, out_ptr; // Wie viele Brot im Korb privat int übrig; Private Lock Lock = New Reentrantlock (); privater Zustand full = lock.newcondition (); privater Zustand leer = lock.newCondition (); // Brot in Korb public void in () {lock.lock (); try {while (links == arr.length) {try {full.await ();} catch (interruptedException i) {i.printstacktrace ();} arr [in_ptr] = neues Bread ("Mianbao", Produzent ++); System.out.println ("das Brot legen:"+arr [in_ptr] .getName ()+"------- in den Korb ["+in_ptr+"]"); links ++; if (++ in_ptr == arr.length) {in_ptr = 0;} leer.Signal (); } endlich {lock.unlock (); }} // Brot aus dem Korb öffentliches Brot () {lock.lock (); try {while (links == 0) {try {leer.await ();} catch (interruptedException i) {i.printstacktrace ();}} bread out_bread = arr [out_ptr]; System.out.println ("Get das Brot:"+out_bread.getName ()+"---------- From Basket ["+out_ptr+"]"); links--; if (++ out_ptr == arr.length) {out_ptr = 0;} full.Signal (); return out_bread; } endlich {lock.unlock (); }}} Klassenbrot {privater String -Name; Bread (String -Name, int num) {this.name = name + num; } public String getName () {return this.name; }} Klasse -Produzent implementiert Runnable {privater Korb; public static int num = 1; // Die erste Nummer für Breads Namensproduzent (Korb b) {this.basket = b; } public void run () {while (true) {basket.in (); try {thread.sleep (10);} catch (InterruptedException i) {}}}} Klasse Consumer Implements Runnable {privater Korb; privates Brot i_get; Verbraucher (Korb b) {this.basket = b; } public void run () {while (true) {i_get = basket.out (); try {thread.sleep (10);} catch (InterruptedException i) {}}}} public class ProduconCononsume_7 {public static void main (String [] args) {Basket b = neuer Korb (20); // die Korbgröße = 20 Produzent Pro = New Producer (B); Consumer con = neuer Verbraucher (B); Thread pro_t1 = neuer Thread (pro); Thread pro_t2 = neuer Thread (pro); Thread con_t1 = neuer Thread (con); Thread con_t2 = neuer Thread (con); Thread con_t3 = neuer Thread (con); pro_t1.start (); pro_t2.Start (); con_t1.start (); con_t2.Start (); con_t3.Start (); }}Dies umfasst Verbraucher, Hersteller, Brot und Körbe, wo Brot und Körbe Ressourcen sind, die von mehreren Fäden betrieben werden. Der Produzentfaden produziert Brot und steckt es in den Korb, und der Verbraucherfaden nimmt das Brot aus dem Korb heraus. Der ideale Code besteht darin, sowohl Produktionsaufgaben als auch Verbrauchsaufgaben in der Ressourcenklasse zu verkörpern. Da Brot ein Element des Korbbehälters ist, ist es nicht zum Verpacken in die Brotklasse geeignet, und das Verpacken in den Korb erleichtert den Betrieb des Behälters.
Beachten Sie, dass Sie alle Codes mit Ressourcenoperationen in das Schloss einfügen müssen, ansonsten treten ein Multi-Thread-Out-Synchronisierungsproblem auf. Zum Beispiel wird die Methode, die Brot produziert, in der Produzentenklasse definiert und dann als Parameter für den Methodenkorb verwendet.
Der obige Artikel basiert auf dem Java -Produzenten- und Verbrauchermodell (detaillierte Analyse) und ist der gesamte Inhalt, der vom Editor geteilt wird. Ich hoffe, es kann Ihnen eine Referenz geben und ich hoffe, Sie können Wulin.com mehr unterstützen.