Vor Java 5.0 wurden die einzigen Mechanismen, die zur Koordinierung des Zugriffs auf gemeinsame Objekte verwendet werden konnten, synchronisiert und flüchtig. Wir wissen, dass das synchronisierte Schlüsselwort integrierte Schlösser implementiert, während das volatile Schlüsselwort die Sichtbarkeit der Speicher für Multi-Threads sicherstellt. In den meisten Fällen können diese Mechanismen den Job gut machen, aber sie können jedoch keine weiteren erweiterten Funktionen implementieren, z. Daher wurde in Java 5.0 ein neuer Mechanismus hinzugefügt: Reentrantlock. Die Reentrantlock -Klasse implementiert die Sperrschnittstelle und liefert die gleiche Sichtbarkeit von Mutex und Speicher wie synchronisiert. Die zugrunde liegende Schicht besteht darin, eine Multi-Thread-Synchronisation durch AQs zu erreichen. Im Vergleich zu eingebauten Schlössern bietet Reentrantlock nicht nur einen reichhaltigeren Verriegelungsmechanismus, sondern auch in den früheren Versionen integrierten Leistungsschlössern (sogar besser als eingebaute Schlösser). Nachdem wir über so viele Vorteile von Reentrantlock gesprochen haben, lassen Sie uns seinen Quellcode aufdecken und die spezifische Implementierung sehen.
1. Einführung in synchronisierte Schlüsselwörter
Java bietet integrierte Schlösser zur Unterstützung der Multi-Thread-Synchronisation. Der JVM identifiziert den synchronisierten Codeblock gemäß dem synchronisierten Schlüsselwort. Wenn ein Thread in den synchronisierten Codeblock eingeht, erfasst er automatisch das Sperre. Beim Verlassen des synchronisierten Codeblocks wird die Sperre automatisch veröffentlicht. Nachdem ein Faden das Schloss erworben hat, werden andere Fäden blockiert. Jedes Java -Objekt kann als Schloss verwendet werden, das die Synchronisation implementiert. Das synchronisierte Schlüsselwort kann verwendet werden, um Objektmethoden, statische Methoden und Codeblöcke zu ändern. Beim Ändern von Objektmethoden und statischen Methoden ist das Schloss das Objekt, an dem sich die Methode befindet, und das Klassenobjekt. Beim Ändern des Codeblocks müssen zusätzliche Objekte als Schlösser bereitgestellt werden. Der Grund, warum jedes Java -Objekt als Schloss verwendet werden kann, ist, dass ein Monitorobjekt (Manipulation) im Objektheader zugeordnet ist. Wenn der Thread in den synchronen Codeblock eingeht, wird das Monitorobjekt automatisch gehalten und wenn er beendet ist, wird das Monitorobjekt automatisch freigegeben. Wenn das Monitorobjekt gehalten wird, werden andere Threads blockiert. Natürlich werden diese Synchronisationsvorgänge von der JVM -zugrunde liegenden Ebene implementiert, aber es gibt immer noch einige Unterschiede in der zugrunde liegenden Implementierung der Methode für synchronisierte Keyword -Modifikationsmethoden und des Codeblocks. Die synchronisierte Keyword -Modifikationsmethode wird implizit synchronisiert, dh sie muss nicht über Bytecode -Anweisungen gesteuert werden. Das JVM kann unterscheiden, ob eine Methode eine synchronisierte Methode ist, die auf dem Acc_Synchronisierten Zugriffsflag in der Methode Tabelle basiert. Während die durch synchronisierten Schlüsselwort modifizierten Codeblöcke explizit synchronisiert sind, steuern die Pipeline des Threads über die Anweisungen von MonitoreExit -Bytecode. Das Monitorobjekt hält das Feld _count intern. _count gleich 0 bedeutet, dass die Pipeline nicht gehalten wird, und _count größer als 0 bedeutet, dass die Pipeline gehalten wurde. Jedes Mal, wenn der Holding-Thread-Wiedereintritt, wird _count 1 hinzugefügt, und jedes Mal, wenn der Holding-Thread ausgeht, wird _count um 1. reduziert. Dies ist das Implementierungsprinzip des integrierten Sperren-Wiedereintritts. Darüber hinaus gibt es zwei Warteschlangen im Monitorobjekt _EnterryList und _waitset, die der Synchronisationswarteschlange und der bedingten Warteschlange von AQs entsprechen. Wenn der Thread das Schloss nicht erfasst, blockiert er in der _Entrylist. Wenn die Wartenmethode des Sperrobjekts aufgerufen wird, gilt der Thread in das Warten des _waitset. Dies ist das Implementierungsprinzip der Threadsynchronisation und des bedingten Wartens auf integrierte Schlösser.
2. Vergleich zwischen Reentrantlock und synchronisiert
Das synchronisierte Schlüsselwort ist ein integrierter Sperrmechanismus von Java. Die Synchronisationsoperationen werden vom zugrunde liegenden JVM implementiert. Reentrantlock ist ein explizites Schloss, das vom Java.util.Concurrent -Paket bereitgestellt wird, und seine Synchronisierungsvorgänge werden vom AQS -Synchronisator betrieben. Reentrantlock bietet die gleiche Semantik bei Verriegelung und Speicher wie eingebaute Schlösser. Darüber hinaus bietet sie einige andere Funktionen, darunter zeitgesteuerte Wartezeiten, Interruptible-Warten, faire Verriegelung und Implementierung von nicht blockiertem Strukturverriegelung. Darüber hinaus hatte Reentrantlock in den frühen JDK -Versionen bestimmte Leistungsvorteile. Warum sollten wir das synchronisierte Schlüsselwort verwenden, da Reentrantlock so viele Vorteile hat? Tatsächlich verwenden viele Menschen Reentrantlock, um den Sperrvorgang synchronisierter Schlüsselwörter zu ersetzen. Eingebaute Schlösser haben jedoch immer noch ihre eigenen Vorteile. Eingebaute Schlösser sind vielen Entwicklern bekannt und einfacher und kompakter. Da explizite Schlösser manuell als Entsperren im endgültigen Block genannt werden müssen, ist es relativ sicherer, integrierte Schlösser zu verwenden. Gleichzeitig verbessert es eher die Leistung von synchronisierten als in Zukunft. Da synchronisiert eine eingebaute Eigenschaft des JVM ist, kann es einige Optimierungen durchführen, z. Wenn also einige fortschrittliche Funktionen benötigt werden, sollte ein Wiedereintrittsprotokoll verwendet werden, darunter: Zeit, zeitliche, befragbare und unterbrechbare Sperraufnahmeoperationen, faire Warteschlangen und Nicht-Block-Strukturschlösser. Andernfalls sollte zuerst synchronisiert werden.
3. Operationen des Erwerbs und Verlassens von Schlösser
Schauen wir uns zunächst den Beispielcode mit Reentrantlock an, um Schlösser hinzuzufügen.
public void dosomething () {// Die Standardeinstellung ist, ein Reentrantlock-Lock von Nicht-Fair-Lock zu erhalten. Versuchen Sie {// lock lock.lock () vor der Ausführung; // Die Operation ausführen ...} endlich {// Die Lock Lock.unlock () veröffentlicht schließlich; }}Das Folgende ist die API für den Erwerb und die Freigabe von Schlössern.
// Der Betrieb der Erlangung von Lock public void lock () {sync.lock ();} // Der Betrieb der Freisetzung von Lock Public void Unlock () {sync.release (1);}Sie können sehen, dass die Operationen des Erwerbs des Schlosses und der Freisetzung des Schlosses an die Verriegelungsmethode und die Freigabemethode des Synchronisierungsobjekts delegiert werden.
öffentliche Klasse Reentrantlock implementiert Lock, Java.io.Serializable {private endgültige Synchronisierung; Abstract statische Klasse Sync erweitert abstrakte SprachköpfeSynchronizer {Abstract void lock (); } // Synchronizer, das nicht-faire Sperre statische endgültige Klasse nicht-fairSync implementiert, synchronisiert {endgültig void lock () {...}} // Synchronizer, die Fair Lock Static Final Class FairSync implementiertJedes Reentrantlock -Objekt enthält eine Referenz der Typ -Synchronisierung. Diese Synchronisierungsklasse ist eine abstrakte innere Klasse. Es erbt von Abstractqueuedsynchronizer. Die Sperrmethode im Inneren ist eine abstrakte Methode. Die Mitgliedsynchronisierung von Reentrantlocks Mitgliedsvariablen wird während der Konstruktion Wert zugewiesen. Schauen wir uns an, was die beiden Konstruktormethoden von Reentrantlock tun?
// Der Standard -Parameterloch -Konstruktor public reentrantlock () {sync = new Nonfairsync ();} // Der parameterisierte Konstruktor Public Reentrantlock (boolean fair) {sync = fair? NEUE FAIRSYNC (): NEU NEUTE FAIRSYNC ();};Wenn Sie den parameterlosen Standardkonstruktor aufrufen, wird die Synchronisierung der nicht fairen Synchronisation die nicht faire Synchronisation zugewiesen, und die Sperre ist zu diesem Zeitpunkt eine Nicht-Fair-Sperre. Mit dem Parameterkonstruktor können Parameter angeben, ob eine FairSYNC -Instanz oder eine nicht faire Synchronisation eine Instanz der Synchronisierung zugewiesen werden soll. Nonfairsync und Fairsync erben sowohl aus der Sync-Klasse als auch die Lock () -Methode neu, sodass einige Unterschiede zwischen fairen Schlössern und nicht-fairen Schlössern zum Erhalt von Schlössern bestehen, über die wir unten sprechen werden. Schauen wir uns den Betrieb der Veröffentlichung des Schlosses an. Jedes Mal, wenn Sie die Unlock () -Methode aufrufen, führen Sie einfach die Sync.Release (1) -Operation aus. In diesem Vorgang wird die Release () -Methode der Abstractqueuedsynchronizer -Klasse aufgerufen. Lassen Sie es uns erneut überprüfen.
// Veröffentlichen Sie den Sperrvorgang (exklusiver Modus) öffentliche endgültige Boolesche Release (int arg) {// Die Kennwortsperrung drehen, um festzustellen, ob sie entsperren kann, wenn (TryRelease (arg)) {// den Kopfknotenknoten h = Kopf abrufen; // Wenn der Kopfknoten nicht leer ist und der Wartezustand nicht gleich 0 ist, wecken Sie den Nachfolgerknoten if (h! = Null && h.waitstatus! } Return true; } return false;}Diese Release -Methode ist die API für die Freigabe von von AQS bereitgestellten Sperrvorgängen. Es ruft zunächst die Tryrelease -Methode auf, um zu versuchen, das Schloss zu erwerben. Die TryRease -Methode ist eine abstrakte Methode, und ihre Implementierungslogik befindet sich in der Subklasse -Synchronisierung.
// Versuchen Sie, das geschützte lock -geschützte boolesche Tryrelease (int releases) {int c = getState () - Releases; // Wenn der Thread, der das Schloss hält, nicht der aktuelle Thread ist, wird eine Ausnahme geworfen, wenn (thread.currentThread ()! } boolean Free = false; // Wenn der Synchronisationsstatus 0 ist, bedeutet dies, dass die Sperre veröffentlicht wird, wenn (c == 0) {// das Flag des Sperre festlegen wird, das als true Free = true veröffentlicht wird; // Setzen Sie den besetzten Thread auf leeres SetExclusiveChinerThread (NULL); } setState (c); Rückkehr frei;}Diese TryRelease -Methode erfasst zunächst den aktuellen Synchronisationszustand, subtrahieren Sie den aktuellen Synchronisationszustand von den übergebenen Parametern in den neuen Synchronisationszustand und bestimmen Sie dann, ob der neue Synchronisationszustand gleich 0 ist. Setzen Sie dann den Release -Status der Sperre auf true, löschen Sie dann den Thread, der derzeit die Sperre einnimmt, und rufen Sie schließlich die SetState -Methode auf, um den neuen Synchronisationszustand festzulegen und den Release -Status der Sperre zurückzugeben.
4. Faires Schloss und unfaires Schloss
Wir wissen, auf welche spezifische Instanz der Wiedereintrittspreis auf der Grundlage der Synchronisation hinweist. Während der Konstruktion wird die Mitgliedervariable -Synchronisierung zugewiesen. Wenn der Wert der nicht fairen Instanz zugeordnet ist, bedeutet dies, dass es sich um eine Nicht-Fair-Sperre handelt. Wenn der Wert der FairSYNC-Instanz zugeordnet ist, bedeutet dies, dass es sich um ein faires Sperre handelt. Wenn es sich um eine faire Sperre handelt, erhalten die Threads die Sperre in der Reihenfolge, in der sie die Anfragen stellen, aber auf der unfairen Sperre ist das Ausschnittverhalten zulässig: Wenn ein Thread eine unlautere Sperre fordert, überspringt der Zustand der Schloss zur gleichen Zeit mit der Anforderung, dass der Thread alle Wartefäden in der Warteschlange überspringt, um das Schloss direkt zu erhalten. Schauen wir uns an, wie Sie unfaire Schlösser erhalten.
// Unfair Synchronizer statische endgültige Klasse Nicht -fairsync erweitert Sync {// Implementieren Sie die abstrakte Methode der übergeordneten Klasse, um die Lock -Final -Void Lock () {// CAS -Methode zu verwenden, um den Synchronisationszustand festzulegen, wenn (VergleicheAndsetState (0, 1)) {// Wenn der Einstellung erfolgreich ist. } else {// ansonsten bedeutet es, dass das Schloss besetzt wurde, erwerbe anrufen und die Thread -Warteschlange so synchronisieren lassen, um die Warteschlange zu synchronisieren, um zu erwerben (1); }} // Die Methode, um zu versuchen, den lock -geschützten endgültigen Booleschen Tryacquire (int zu erwerben) {Return NonfairtryAcquire (erwirbt); }} // Erwerben Sie Sperren im nicht-interrupten Modus (exklusiver Modus) öffentlicher endgültiger Leere erwerben (int arg) {if (! Tryacquire (arg) && accoderqueued (addwaiter (node.exclusive), arg)) {selfterrupt (); }}Es ist ersichtlich, dass in der Sperrmethode der unfairen Schloss der Thread den Wert des Synchronisationszustands im ersten Schritt in CAS von 0 auf 1 ändert. Tatsächlich entspricht dieser Vorgang dem Versuch, das Schloss zu erwerben. Wenn die Änderung erfolgreich ist, bedeutet dies, dass der Thread gerade das Schloss erworben hat und es nicht mehr erforderlich ist, in der Synchronisationswarteschlange anzustellen. Wenn die Änderung fehlschlägt, bedeutet dies, dass das Schloss nicht veröffentlicht wurde, wenn der Thread zum ersten Mal kommt. Die Erwerbsmethode wird daher als nächstes aufgerufen. Wir wissen, dass diese Erwerbsmethode von der Abstractqueuedsynchronizer -Methode vererbt wird. Lassen Sie uns diese Methode überprüfen. Nachdem der Thread in die Erwerbsmethode eingetreten ist, ruft der erste Aufruf der Tryacquire -Methode, um zu versuchen, das Schloss zu erwerben. Da nicht fairSync die Tryacquire -Methode überschreibt und die nicht fairtryacquire -Methode der übergeordneten Klassensynchronisierung in der Methode aufruft, wird die nicht fairtryacquire -Methode hier aufgerufen, um zu versuchen, das Schloss zu erwerben. Mal sehen, was diese Methode speziell macht.
// Unfaire Erfassung des locken endgültigen booleschen Nicht -Fairtryacquire (int erwirbt) {// den aktuellen Thread Final Thread Current = Thread.CurrentThread () abrufen; // Erhalten Sie den aktuellen Synchronisationszustand int c = getState (); // Wenn der Synchronisationszustand 0 ist, bedeutet dies, dass die Sperre nicht besetzt ist, wenn (c == 0) {// CAS zum Aktualisieren des Synchronisationsstatus if (vergleicheStSetState (0, erwirbt)) {// den Thread festlegen, der derzeit den SperrsetExclusive -Thread (aktuell) belegt; zurückkehren; } // Ansonsten wird festgestellt, ob die Sperre der aktuelle Thread ist} else if (current == getExclusiveCorneerThread ()) {// Wenn die Sperre vom aktuellen Thread gehalten wird, ändern Sie direkt den aktuellen Synchronisationszustand int NextC = C + Erwerb; if (nextc <0) {Neuen Fehler werfen ("Maximale Sperrzahl überschritten"); } setState (nextc); zurückkehren; } // Wenn die Sperre nicht der aktuelle Thread ist, geben Sie das Fehlerflag zurück.Die nicht fairtryacquire -Methode ist eine Synchronisierungsmethode. Wir können sehen, dass nach dem Eintritt in diese Methode zuerst der Synchronisationszustand erfasst wird. Wenn der Synchronisationszustand 0 ist, verwenden Sie den CAS -Betrieb, um den Synchronisationszustand zu ändern. In der Tat soll dies das Schloss erneut erwerben. Wenn der Synchronisationszustand nicht 0 ist, bedeutet dies, dass das Schloss besetzt ist. Zu diesem Zeitpunkt werden wir zunächst bestimmen, ob der Faden, der das Schloss hält, der aktuelle Thread ist. In diesem Fall wird der Synchronisationszustand um 1. erhöht. Andernfalls wird der Betrieb des Versuchs, das Schloss zu erwerben, fehlschlägen. Daher wird die Addwaiter -Methode aufgerufen, um den Thread zur Synchronisationswarteschlange hinzuzufügen. Zusammenfassend lässt sich sagen, dass ein Thread im unfairen Sperrmodus zwei Schlösser erwerben, bevor er in die Synchronisationswarteschlange eintritt. Wenn die Akquisition erfolgreich ist, wird die Warteschlange der Synchronisation Warteschlange nicht eingegeben, andernfalls wird die Warteschlangewarteschlange der Synchronisierungswarteschlange eingegeben. Schauen wir uns als nächstes an, wie Sie faire Schlösser erhalten.
// Synchronizer, die die statische Fairsync der Fair Lock implementiert, erweitert Sync {// Implementieren Sie die abstrakte Methode der übergeordneten Klasse, um die locking void lock () {// Call Acciriere aufzurufen, und lassen Sie die Thread -Warteschlange, um die Warteschlange zu synchronisieren, um die Warteschlange zu synchronisieren (1); } // Versuchen Sie, das geschützte lock -geschützte endgültige Boolesche Tryacquire (int zu erwerben) {// den aktuellen Thread Final Thread Current = Thread.CurrentThread () abrufen; // Erhalten Sie den aktuellen Synchronisationszustand int c = getState (); // Wenn der Synchronisationszustand 0 bedeutet, dass das Schloss nicht besetzt ist, wenn (c == 0) {// verteidigen, ob es einen Vorwärtsknoten in der Synchronisations -Warteschlange gibt, wenn (! HaSqueedPred -Angänger () && VergleicheStatstate (0, erwirbt) {// Wenn es keinen Vorwärtsnoten gibt und der Synchronisierungszustand erfolgreich ist, ist das Synchronisierungszustand eingestellt. setExclusiveWererThread (aktuell); zurückkehren; } // Ansonsten bestimmen Sie, ob der aktuelle Thread die Sperre enthält if (nextc <0) {Neuen Fehler werfen ("Maximale Sperrzahl überschritten"); } setState (nextc); zurückkehren; } // Wenn der aktuelle Thread die Sperre nicht enthält, schlägt die Akquisition falsch zurück. }} Wenn Sie die Sperrmethode des Fair Lock aufrufen, wird die Erwerbsmethode direkt aufgerufen. In ähnlicher Weise ruft die Erwerbsmethode zunächst die Fairsync Rewrite Tryacquire -Methode auf, um das Schloss zu erwerben. Bei dieser Methode wird zunächst der Wert des Synchronisationszustands erhalten. Wenn der Synchronisationszustand 0 beträgt, bedeutet dies, dass das Schloss zu diesem Zeitpunkt veröffentlicht wird. Der Unterschied zum unfairen Schloss besteht darin, dass es zuerst die Methode der HasqueuepreedPred -Anbieter bezeichnet, um zu überprüfen, ob jemand in der Synchronisationswarteschlange an der Warteschlange stellt. Wenn sich niemand anstellt, wird der Wert des Synchronisationszustands geändert. Sie können sehen, dass das Fair Lock hier eine Höflichkeitsmethode annimmt, anstatt das Schloss sofort zu erwerben. Abgesehen von diesem Schritt, der sich von der unfairen Schloss unterscheidet, sind die anderen Operationen gleich. Zusammenfassend können wir sehen, dass die Fair -Sperre nur den Status der Sperre überprüft, bevor sie in die Synchronisationswarteschlange eintreten. Selbst wenn Sie feststellen, dass das Schloss offen ist, werden Sie es nicht sofort erwerben. Stattdessen lassen Sie die Threads in der Synchronisationswarteschlange zuerst erwerben. Daher kann sichergestellt werden, dass die Reihenfolge, in der alle Threads die Schlösser unter dem Fair -Lock erwerben, zuerst und dann eingetroffen ist, was auch die Fairness der Erlangung der Schlösser sicherstellt.
Warum wollen wir nicht, dass alle Schlösser fair sind? Schließlich ist Fairness ein gutes Verhalten und Ungerechtigkeit ist ein schlechtes Verhalten. Da die Suspend- und Weckvorgänge des Threads einen großen Overhead aufweisen, wirkt sich dies auf die Systemleistung aus, insbesondere bei heftigem Wettbewerb, faire Schlösser werden zu häufigen Suspend- und Weckvorgängen von Threads führen, während Nicht-Fair-Schlösser solcher Vorgänge reduzieren können, sodass sie besser als faire Schleusen in der Leistung sind. Da die meisten Threads Sperrungen für eine sehr kurze Zeit verwenden und der Weckbetrieb des Threads eine Verzögerung aufweist, ist es möglich, dass Thread B das Schloss sofort erfasst und das Schloss nach der Verwendung freigibt. Dies führt zu einer Win-Win-Situation. In dem Moment, in dem Faden A erwerben, wird das Schloss nicht verzögert, aber das Gewinde B verwendet das Schloss im Voraus und der Durchsatz wurde ebenfalls verbessert.
5. Der Implementierungsmechanismus der bedingten Warteschlangen
Es gibt einige Mängel in der integrierten Warteschlange. Jedes integrierte Schloss kann nur eine zugeordnete Bedingungswarteschlange haben, wodurch mehrere Threads auf unterschiedliche Zustandsprädikate in derselben Bedingungswarteschlange warten. Jedes Mal, wenn Benachrichtigung aufgerufen wird, werden alle Wartefäden geweckt. Wenn der Faden aufwacht, wird festgestellt, dass es nicht das Prädikat des Zustands ist, auf das er wartet, und er wird suspendiert. Dies führt zu vielen nutzlosen Weck- und Suspend-Operationen, die viele Systemressourcen verschwenden und die Systemleistung verringern. Wenn Sie ein gleichzeitiges Objekt mit mehreren bedingten Prädikaten schreiben möchten oder wenn Sie mehr Kontrolle als bedingte Sichtbarkeit erhalten möchten, müssen Sie explizite Sperre und Zustand anstelle von integrierten Schlössern und bedingten Warteschlangen verwenden. Ein Zustand und ein Schloss sind wie eine Bedingungswarteschlange und ein integriertes Schloss miteinander verbunden. Um eine Bedingung zu erstellen, können Sie die Methode Lock.NewCondition auf der zugehörigen Sperre aufrufen. Schauen wir uns zunächst ein Beispiel mit Bedingung an.
öffentliche Klasse bodedBuffer {Final Lock Lock = New Reentrantlock (); endgültige Bedingung Notfull = lock.newcondition (); // Bedingung Prädikat: Notfull Endbedingung NotonMpty = lock.NewCondition (); // Bedingung Prädikat: Notizty Final Object [] items = New Object [100]; int putptr, takeptr, zählen; // Produktionsmethode public void put (Objekt x) löscht InterruptedException {lock.lock (); try {while (count == items.length) notfull.await (); // Die Warteschlange ist voll, und der Thread wartet auf Elemente [PutPtr] in der Notfloy -Warteschlange. Elemente [putptr] = x; if (++ putptr == items.length) putptr = 0; ++ Count; notieren.Signal (); // Produktion ist erfolgreich, wecke den Knoten der Notizty Queue} endlich {lock.unlock (); }} // Verbrauchsmethode öffentliches Objekt take () löscht InterruptedException {lock.lock (); try {while (count == 0) Notizty.aait (); // Die Warteschlange ist leer, Thread wartet auf Objekt x = Elemente [takeptr] in der notwendigen Warteschlange; if (++ takeptr == items.length) takeptr = 0; --zählen; Notfurl.Signal (); // Konsum ist erfolgreich, weckt den Knoten der Notfuloy Queue Return X; } endlich {lock.unlock (); }}}Ein Schlossobjekt kann mehrere Zustandswarteschlangen erzeugen, und zwei Bedingungswarteschlangen werden hier nicht generiert und notwendig generiert. Wenn der Container voll ist, muss der Thread, der die Put -Methode aufruft, blockiert werden. Warten Sie, bis das Prädikat des Zustands wahr ist (der Container ist nicht erfüllt), wacht auf und führt weiter aus. Wenn der Container leer ist, muss der Thread, der die Take -Methode aufruft, blockiert werden. Warten Sie, bis das Prädikat des Zustands wahr ist (der Container ist nicht leer), wacht auf und führt weiter aus. Diese beiden Arten von Threads warten nach Prädikaten mit unterschiedlichen Bedingungen, sodass sie zwei verschiedene Bedingungswarteschlangen eingeben und bis zum richtigen Zeitpunkt warten, bevor Sie die API unter dem Bedingungsobjekt aufrufen. Das Folgende ist der Implementierungscode der Newcondition -Methode.
// Erstellen Sie eine Bedingungswarteschlange für öffentliche Bedingung NewCondition () {return sync.newcondition ();} Abstract statische Klasse Sync erweitert AbstractQueuedsynchronizer {// Erstellen Sie ein neues Bedingungsobjekt endgültiges ZustandObject NewCondition () {return New ConditionObject (); }}Die Implementierung der Bedingungswarteschlange zu Reentrantlock basiert auf Abstractqueuedsynchronizer. Das Bedingungsobjekt, das wir beim Aufrufen der Newcondition -Methode erhalten, ist eine Instanz des internen Klassenbedingungsprojekts von AQs. Alle Vorgänge unter Bedingungswarteschlangen werden durchgeführt, indem die API von ConditionObject aufgerufen wird. Für eine spezifische Implementierung von ConditionObject können Sie meinen Artikel "Java-Concurrency-Serie [4] ----- AbstractQueuedsynchronizer Quellcode-Analyse Bedingte Warteschlange" überprüfen, und ich werde es hier nicht wiederholen. Zu diesem Zeitpunkt ist unsere Analyse des Quellcode von Reentrantlock zu Ende gegangen. Ich hoffe, dass das Lesen dieses Artikels den Lesern hilft, Reentrantlock zu verstehen und zu meistern.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.