Durch die Analyse der vorherigen drei Artikel haben wir ein tiefes Verständnis der internen Struktur und einige Designkonzepte von Abstractqueuedsynchronizer, und wir wissen, dass AbstractQueuedsynchronizer einen Synchronisationszustand bzw. zwei Warteschlangenbereiche beibehält, die synchrone Warteschlangen bzw. bedingten Warteschlangen sind. Nutzen wir öffentliche Toiletten als Analogie. Die Synchronisationswarteschlange ist die Hauptwarteschlange. Wenn die öffentlichen Toiletten nicht geöffnet sind, muss jeder, der die Toilette betreten möchte, hier anstehen. Die Bedingungswarteschlange ist hauptsächlich für das Warten von Bedingung eingestellt. Stellen wir uns vor, wenn eine Person endlich erfolgreich das Schloss erhält und durch die Warteschlange in die Toilette eintritt, aber feststellt, dass sie vor der Bequemlichkeit kein Toilettenpapier mitbringt. Obwohl er bei der Begegnung dieser Situation hilflos ist, muss dies auch diese Tatsache akzeptieren. Zu diesem Zeitpunkt muss es zuerst ausgehen und das Toilettenpapier vorbereiten (betreten Sie die Warteschlange, um zu warten). Natürlich muss das Schloss vor dem Ausgehen veröffentlicht werden, damit andere hereinkommen können. Nach der Vorbereitung des Toilettenpapiers (die Bedingungen werden erfüllt) müssen sie in die synchrone Warteschlange zurückkehren, um erneut Warteschlangen zu halten. Natürlich brachten nicht alle Menschen, die den Raum betraten, nicht Toilettenpapier. Es kann andere Gründe geben, warum sie die Operation unterbrechen und zuerst in der Bedingung in der Warteschlange stehen müssen. Daher kann es mehrere Zustandswarteschlangen geben, und es werden unterschiedliche Bedingungswarteschlangen gemäß unterschiedlichen Wartezeiten festgelegt. Die Bedingungswarteschlange ist eine einseitige verlinkte Liste. Die Bedingungsschnittstelle definiert alle Vorgänge in der Bedingungswarteschlange. Die ConditionObject -Klasse innerhalb des Abstractquedsynchronizers implementiert die Bedingungsschnittstelle. Schauen wir uns an, welche Vorgänge durch die Bedingungsschnittstelle definiert werden.
öffentliche Schnittstellenbedingung {// Warten auf die Reaktion auf Thread -Unterbrechung Void Await () löscht InterruptedException aus; // Warten darauf zu warten, dass nicht auf Fadenunterbrecher -Leere wartet, wartetUnterriptable (); // Bedingung auf relative Zeit einstellen (kein Spin), long wartnanos (langlange Nanostimeout) unterbrochene InterruptedException; // BOOLEAN SETTIERENDE WARTE -Bedingung auf relative Zeit (Spin), die boolean wartet (lange Zeit, Zeiteinheit) unterbrochene InterruptedException; // Bedingung auf Absolute Zeit einstellen, die boolean wartete, löst die InterruptedException aus; // Weck den Kopfknoten void Signal () in der Bedingungswarteschlange; // wach alle Knoten der Bedingungswarteschlange void signalall () auf; }Obwohl die Bedingungsschnittstelle so viele Methoden definiert, ist sie insgesamt in zwei Kategorien unterteilt. Die Methode, die mit Warten beginnt, ist die Methode, die die Bedingungswarteschlange und die Warteschlange eingibt, und die Methode, die mit Signal beginnt, ist die Methode, die den Thread in der Bedingungswarteschlange "aufweckt". Es ist hier zu beachten, dass das Aufrufen der Signalmethode den Thread aufweckt oder nicht. Wenn der Thread erweckt wird, hängt abhängig von der Situation ab, wie später erläutert wird. Wenn Sie jedoch die Signalmethode aufrufen, wird der Thread definitiv von der bedingten Warteschlange zum Schwanz der Synchronisationswarteschlange verschoben. Aus Gründen der Erzählung werden wir uns vorerst keine Sorgen machen. Wir nennen die Signalmethode den Betrieb des wecken bedingten Warteschlangen-Threads. Bitte beachten Sie, dass es 5 Arten von Warteverfahren gibt, nämlich das Warten des Response-Thread-Interrupts, das Warten des Nicht-Reaktion-Threads, das Warten des relativen Zeitpunkts, das Warten des relativen Zeitspins und das Warten der absoluten Zeit; Es gibt nur zwei Arten von Signalmethoden, nämlich den Betrieb, das nur den Zustand des Bedingungswarteschlangens und des Erwachens aller Knoten der Bedingungswarteschlange erweckt. Die gleiche Art von Methoden ist im Grunde die gleiche. Aus Platzbeschränkungen ist es unmöglich und nicht notwendig, sorgfältig über diese Methoden zu sprechen. Wir müssen nur eine repräsentative Methode verstehen und dann andere Methoden betrachten, um sie zu verstehen. In diesem Artikel werde ich also nur im Detail über die wartende Methode und die Signalmethode sprechen. Andere Methoden werden nicht ausführlich besprochen, sondern den Quellcode für Ihre Referenz veröffentlichen.
1. Warten Sie auf die Reaktion auf den Zustand des Thread -Interrupts
// Warten auf die Bedingung des Thread Interrupt Public Final Leere Warted () löscht InterruptedException (// Wenn der Thread unterbrochen wird, wird eine Ausnahme ausgeworfen, wenn (thread.interrupted ()) {neue InterruptedException () auswirken; } // Fügen Sie den aktuellen Thread zum Schwanz der Bedingungswarteschlange Node Node = AddConDitionWaiter () hinzu; // Vollständige Veröffentlichung der Sperre vor dem Eingeben der Bedingung Wait Int sparedState = vollständige (Knoten); int interruptMode = 0; // Der Thread hat in der WHOR -Schleife während des WHOS -Schleifens gewartet (! IsonSyncQueue (Knoten)) {// Der Thread, der bedingt wartet, wird hier suspendiert. Es gibt mehrere Fälle, in denen der Thread erweckt wird: // 1. Der Vorwärtsknoten der Synchronisationswarteschlange wurde abgebrochen // 2. Setzen Sie den Status des Vorwärtsknotens der Synchronisationswarteschlange auf das Signal fehlgeschlagen // 3. Der aktuelle Knoten wird geweckt, nachdem der Vorwärtsknoten das Schloss veröffentlicht hat. // Der aktuelle Thread prüft sofort, ob er unterbrochen wird. Wenn ja, bedeutet dies, dass der Knoten die Wartezeit abbricht. Zu diesem Zeitpunkt muss der Knoten aus der Bedingungswarteschlange herausgeholt werden, wenn ((InterruptMode = CheckInterrupt thewaiting (Knoten))! = 0) {Break; }} // Nachdem der Thread aufgewacht ist, wird das Sperre im exklusiven Modus erfasst, wenn (erwerben (knoten, speichert) && interruptMode! } // Dieser Vorgang dient hauptsächlich, um zu verhindern, dass Fäden vor dem Signal unterbrechen, was zu einer Trennung von der Bedingungswarteschlange ist, wenn (node.nextWaiter! = Null) {UnlinkCancelledWaiter (); } // Verarbeitung unterbrechen, die auf den Interrupt -Modus reagiert if (InterruptMode! }}Wenn ein Thread die wartende Methode aufruft, wird der aktuelle Thread als Knotenknoten verpackt und in den Schwanz der Zustandswarteschlange platziert. In der AddConditionWaiter -Methode wird die methode unlinkCancelledWaiters aufgerufen, um alle abgebrochenen Knoten der Bedingungswarteschlange zu löschen, wenn sich der Endknoten der Bedingungswarteschlange festgestellt hat. Dieser Schritt ist die Vorbereitung zum Einfügen von Knoten. Nachdem sichergestellt wurde, dass der Status des Heckknotens ebenfalls Zustand ist, wird ein neuer Knoten erstellt, um den aktuellen Faden zu wickeln und in den Schwanz der Zustandswarteschlange zu legen. Beachten Sie, dass dieser Vorgang nur Knoten zum Schwanz der Synchronisationswarteschlange hinzufügt, ohne Threads zu suspendieren.
Schritt 2: Ganze das Schloss vollständig los
// Vollständige Veröffentlichung des Sperrens Final INT Vollrelease (Knotenknoten) {boolean failed = true; Versuchen Sie {// den aktuellen Synchronisationszustand int savedState = getState () erhalten; // Verwenden Sie den aktuellen Synchronisationsstatus, um die Sperre zu veröffentlichen, wenn (Release (gespeichert)) {failed = false; // Wenn das Schloss erfolgreich veröffentlicht wird, return savedState; } else {// Wenn das Schloss fehlschlägt, werfen Sie eine Laufzeit -Ausnahme, die neue illegaleMonitorStateException () veröffentlichen; }} schließlich {// Stellen Sie sicher, dass der Knoten auf den Stornierungsstatus gesetzt ist, wenn (fehlgeschlagen) {node.waitstatus = node.cancelled; }}}Nachdem der aktuelle Gewinde in einen Knoten eingepackt und dem Schwanz der Zustandswarteschlange hinzugefügt wurde, wird die vollständige Methode aufgerufen, um die Sperre loszulassen. Beachten Sie, dass die Methode namens Vollrelease verwendet wird, um das Schloss vollständig freizugeben, da das Schloss wieder eingetreten ist. Sie müssen also das Schloss vor bedingten Warten freigeben, andernfalls können andere das Schloss nicht erwerben. Wenn das Schloss fehlschlägt, wird eine Laufzeitausnahme ausgelöst. Wenn das Schloss erfolgreich veröffentlicht wird, kehrt sie zum vorherigen Synchronisationszustand zurück.
Schritt 3: Bedingungen warten
// Der Thread hat in der WHOS -Schleife gewartet (! IsonSyncQueue (Knoten)) {// Die Threads, die auf den Zustand warten, werden hier suspendiert. Es gibt mehrere Fälle, in denen der Faden erweckt wird: // 1. Der Vorwärtsknoten der Synchronisationswarteschlange wurde abgebrochen // 2. Setzen Sie den Status des Vorwärtsknotens der Synchronisationswarteschlange auf das Signal fehlgeschlagen // 3. Der aktuelle Knoten wird geweckt, nachdem der Vorwärtsknoten das Schloss veröffentlicht hat. Locksupport.park (this); // Der aktuelle Thread wächst sofort auf, um zu überprüfen, ob er unterbrochen wird. Wenn ja, bedeutet dies, dass der Knoten die Wartezeit abbricht. Zu diesem Zeitpunkt muss der Knoten aus der Bedingungswarteschlange herausgeholt werden, wenn ((InterruptMode = CheckInterrupt thewaiting (Knoten))! = 0) {Break; }} // Überprüfen Sie die Thread -Unterbrechungssituation, wenn Bedingung Wartezeit von privatem Int -Check -Interrupt -Waiting (Knotenknoten) {// Die Interrupt -Anforderung erfolgt vor der Signaloperation: Throw_ie // Die Interrupt -Anforderung erfolgt nach der Signaloperation: Neuinterbust // Die Interrupt -Anforderung wurde empfangen: 0 Rückgabe -Thread.inrupted ()? (TransferAfterCancelledWait (Knoten)? Throw_ie: Neuinterpretat): 0;} // Übertragen Sie den Knoten, der die Bedingung aus der Bedingungswarteschlange auf die Synchronisationswarteschlange storniert Node.Condition, 0)) {// Nach erfolgreicher Statusänderung den Knoten in den Schwanz der Synchronisationswarteschlange Enq (Knoten) einlegen; zurückkehren; } // Dies zeigt an, dass die CAS -Operation fehlgeschlagen ist, was darauf hinweist, dass der Interrupt nach der Signalmethode auftritt (! IsonSyncqueue (Knoten)) {// Wenn die Sinal -Methode den Knoten nicht auf die Synchronisationswarteschlange übertragen hat, warten Sie auf Thread.yield (); } return false;}Nach Abschluss der beiden oben genannten Operationen wird die while -Schleife gelangen. Sie können sehen, dass die While -Schleife zuerst calls locksupport.park (this) zum Aufhängen des Threads aufruft, sodass der Thread die ganze Zeit hier blockiert wird. Übertragen Sie nach dem Aufrufen der Signalmethode den Knoten einfach von der bedingten Warteschlange in die Synchronisationswarteschlange. Ob der Faden erweckt wird, hängt von der Situation ab. Wenn Sie feststellen, dass der Vorwärtsknoten in der Synchronisationswarteschlange beim Übertragen eines Knotens storniert wird oder der Status des Vorwärtsknotens auf Signal fehlgeschlagen ist, weckt beide Fälle sofort den Thread. Andernfalls wird der Faden, der bereits in der Synchronisationswarteschlange befindet, am Ende der Signalmethode nicht geweckt, sondern wartet, bis sein Vorwärtsknoten aufwacht. Natürlich kann der Thread nicht nur die Signalmethode zum Aufwachen aufrufen, sondern auch auf Interrupts reagieren. Wenn der Thread hier eine Interrupt -Anfrage empfängt, wird er weiterhin ausgeführt. Sie können sehen, dass nach dem Aufwachen des Threads sofort prüft, ob er durch Interrupt oder Signalmethode geweckt wird. Wenn es durch Interrupt geweckt wird, überträgt es diesen Knoten auch in die Synchronisationswarteschlange, wird jedoch erreicht, indem die Methode für TransferAftercelledWait aufgerufen wird. Nach der endgültigen Ausführung dieses Schritts wird der Interrupt zurückgegeben und die während der Schleife herausgesprungen.
Schritt 4: Der Betrieb nach dem Knoten wurde aus der Bedingungswarteschlange entfernt
// Nach dem Aufwachen des Threads wird das Sperre im exklusiven Modus erfasst, wenn (erwerben (Knoten, gespeichert) && InterruptMode! UnlinkCancelledWaiter ();} // Interrupt -Verarbeitung, die auf den Interrupt -Modus reagiert, if (InterruptMode! if (interruptMode == throw_ie) {throw New InterruptedException (); // Wenn der Interrupt -Modus neu interpretpiert ist, hängt er sich selbst ab} else if (interruptMode == neu) {selfInterrupt (); }}Wenn der Thread die while -Schleife endet, dh die Bedingung wartet, kehrt sie zur Synchronisationswarteschlange zurück. Unabhängig davon, ob es darum geht, die Signalmethode zurückzufordern oder die Thread -Unterbrechung zu machen, der Knoten wird schließlich in der synchronen Warteschlange stehen. Zu diesem Zeitpunkt wird die Erwerbsmethode aufgerufen, um den Betrieb von Erwerben in der Synchronisationswarteschlange durchzuführen. Wir haben diese Methode bereits im exklusiven Modus -Artikel ausführlich besprochen. Mit anderen Worten, nachdem der Knoten aus der Bedingungswarteschlange herauskommt, geht er gehorsam in den Set von Schlössern im exklusiven Modus. Nachdem dieser Knoten die Sperre erneut erfasst hat, wird die meldestinruptAfterwait -Methode aufgerufen, um entsprechend auf der Grundlage der Interrupt -Situation in diesem Zeitraum zu reagieren. Wenn der Interrupt vor der Signalmethode auftritt, ist InterruptMode Throwd_ie, und eine Ausnahme wird nach dem Erhalt des Schloss erneut ausgelöst. Wenn der Interrupt nach der Signalmethode auftritt, wird InterruptMode erneut uneingeschränkt und wird erneut unterbrochen, nachdem das Schloss erneut erhalten wurde.
2. Warten auf Nichtantwort auf Thread-Interrupts
// Waiting Public Final Void AwaitUnterriptable () {// den aktuellen Thread zum Schwanz der Bedingungswarteschlange Node Node = addConditionWaiter () hinzufügen; // Vollständige Veröffentlichung der Sperre und zurückgeben und den aktuellen Synchronisationszustand in int SavedState = vollständigRelease (Knoten) zurückgeben; boolean unterbrochen = falsch; // Die Knoten warten bedingt in der while -Loop (! IsonSyncQueue (Knoten)) {// Alle Threads in der Bedingungswarteschlange werden hier gesperrt locksupport.park (this); // Der Thread wacht auf und stellt fest, dass der Interrupt nicht sofort reagiert, wenn (thread.interrupted ()) {interrupted = true; }} if (erwerbenqueued (Knoten, gespeichert) || unterbrochen) {// Auf alle Interrupt -Anfragen reagieren, wenn eine der folgenden zwei Bedingungen erfüllt ist, hängt sie selbst auf // 1. Der Thread empfängt die Interrupt -Anforderung, während die Bedingung wartet // 2. Der Thread empfängt die Interrupt -Anforderung in der Accirequed -Methode selfterrupt (); }}3. Setzen Sie das relative Zeitzustand warten (kein Spin)
// Setzen Sie die Zeitwartung des Zeitpunkts (relative Zeit) und führen Sie keine Spin -Wartezeit -Öffentlichkeit länger aus. } // Fügen Sie den aktuellen Thread zum Schwanz der Bedingungswarteschlange Node Node = AddConDitionWaiter () hinzu; // Vollständige Veröffentlichung des Schlosses vor Eingabe des Bedingung Warted int savedState = vollständige (Knoten); lange lastTime = system.nanotime (); int interruptMode = 0; while (! isonSyncQueue (Knoten)) {// beurteilen Sie, ob das Timeout aufgebraucht ist, wenn (Nanostimeout <= 0l) {// Wenn die Zeitüberschreitung abgeschlossen wurde, müssen Sie die Abbrechen -Bedingungsbedingung TRANSPERCANCELLEDWAID (Knoten) ausführen; brechen; } // den aktuellen Thread für einen bestimmten Zeitraum hängen, der Thread kann in dieser Zeit geweckt werden oder er kann von sich selbst aufwachen. // Überprüfen Sie zuerst die Interrupt -Informationen, nachdem der Thread aufgewacht ist, wenn ((InterruptMode = checkEnterrupt thewaiting (Knoten))! = 0) {Break; } long Now = System.nanotime (); // Zeitüberschreitungszeit abzüglich der Wartezeit des Zustands Nanostimeout - = jetzt - letztes Mal; lastTime = jetzt; } // Nachdem der Thread aufgewacht ist, wird das Sperre im exklusiven Modus erfasst, wenn (erwerben (Knoten, gespeichert) && interruptMode! } // Weil die Methode von TransferAfterCancelledWait NEXTWAITER nicht leer ist, müssen Sie hier alles aufräumen, wenn (node.nextWaiter! = Null) {unlinkCancelledWaiter (); } // Verarbeitung unterbrechen, die auf den Interrupt -Modus reagiert if (InterruptMode! } // Die verbleibende Zeit return nanostimeout - (system.nanotime () - letztmal);}4. Stellen Sie das relative Zeitzustand ein (Spin)
// Setzen Sie die zeitgesteuerte Bedingung Warten (relative Zeit), führen Sie das Spin -Waiting Public Final Boolean auf (lange Zeit, Timeunit Unit) unterbrochene InterruptedException {if (uneinheit == null) {werfen neuer nullpointerexception (); } // Erhalten Sie die Millisekunden der Zeitüberschreitung long nanostimeout = unit.tonanos (Zeit); // Wenn der Thread unterbrochen wird, wird eine Ausnahme geworfen, wenn (thread.interrupted ()) {neue InterruptedException () werfen; } // Fügen Sie den aktuellen Thread zum Schwanz der Bedingungswarteschlange Node Node = AddConDitionWaiter () hinzu; // Vollständige Veröffentlichung der Sperre vor dem Eingeben der Bedingung zum Warten von int sparedState = vollständigRelease (Knoten); // die Millisekunden der aktuellen Zeit lange last time = System.nanotime () erhalten; boolean Timedout = false; int interruptMode = 0; while (! isonSyncQueue (Knoten)) {// Wenn eine Zeitüberschreitung zeitlich ist, müssen Sie die Wartevoroperation des Abbrechens durchführen, wenn (Nanostimeout <= 0l) {TimEdout = TransferAfTerCancelledWait (Knoten); brechen; } // Wenn die Zeitüberschreitungszeit größer als die Spin -Zeit ist, wird der Thread für einen bestimmten Zeitraum suspendiert, wenn (Nanostimeout> = spinForForimeoutThreshold) {locksSupport.parknanos (this, nanostimeout); } // Nachdem der Thread aufgewacht ist, überprüft zuerst die Interrupt -Informationen, wenn ((InterruptMode = checkEnterrupt thewaiting (Knoten))! = 0) {Break; } long Now = System.nanotime (); // Zeitüberschreitungszeit subtrahiert jedes Mal die Zeit des Zustands, der nanostimeout - = nun - letztes Mal; lastTime = jetzt; } // Nachdem der Thread aufgewacht ist, wird das Sperre im exklusiven Modus erfasst, wenn (erwerben (Knoten, gespeichert) && interruptMode! } // Da die Methode von TransferAfterCancelledWait NEXTWAICER nicht leer ist, müssen Sie hier alles aufräumen, wenn (node.nextWaiter! = Null) {unlinkCancelledWaiter (); } // Verarbeitung unterbrechen, die auf den Interrupt -Modus reagiert if (InterruptMode! } // Gibt zurück, ob das Timeout -Flag zurückgibt! Timedout;}5. Stellen Sie den absoluten Zeitzustand ein
// Setzen Sie die zeitgesteuerte Bedingung warten (Absolute Zeit) öffentliches Final Boolean Awitunctil (Datum der Deadline) löscht InterruptedException {if (Deadline == NULL) {werfen neu nullPoInterException (); } // Erhalten Sie die Millisekunden von absoluter Zeit lang, long abstime = Deadline.getTime (); // Wenn der Thread unterbrochen wird, wird eine Ausnahme geworfen, wenn (thread.interrupted ()) {neue InterruptedException () werfen; } // Fügen Sie den aktuellen Thread zum Schwanz der Bedingungswarteschlange Node Node = AddConDitionWaiter () hinzu; // Vollständige Veröffentlichung der Sperre vor dem Eingeben der Bedingung Wait Int sparedState = vollständige (Knoten); boolean Timedout = false; int interruptMode = 0; while (! isonSyncQueue (Knoten)) {// Wenn Timeout, müssen Sie einen Wartevorgang des Abbrechens durchführen, wenn (system.currentTimillis ()> Abstime) {TimEdout = TransferAfTerCancelledWait (Knoten); brechen; } // den Faden für einen bestimmten Zeitraum hängen, in dem der Faden erweckt werden kann, oder es kann an der Zeit sein, von sich selbst aufzuwachen. // Überprüfen Sie zuerst die Interrupt -Informationen, nachdem der Thread aufgewacht ist ((InterruptMode = checkEnterrupt thewaiting (Knoten))! = 0) {Break; }} // Nachdem der Thread aufgewacht ist, wird das Sperre im exklusiven Modus erfasst, wenn (erwerben (knoten, speichert) && interruptMode! } // Weil die Methode von TransferAfterCancelledWait NEXTWAITER nicht leer ist, müssen Sie hier alles aufräumen, wenn (node.nextWaiter! = Null) {unlinkCancelledWaiter (); } // Verarbeitung unterbrechen, die auf den Interrupt -Modus reagiert if (InterruptMode! } // Gibt zurück, ob das Timeout -Flag zurückgibt! Timedout;}6. Weck den Kopfknoten in der bedingten Warteschlange auf
// Wach den nächsten Knoten in der Bedingungswarteschlange öffentlich final void signal () {// beurteilen, ob der aktuelle Thread das Schloss enthält, wenn (! ISheldexclusiv ()) {neue IllegalMonMonitorStateException () werfen; } Node first = FirstWaiter; // Wenn sich ein Queueer in der Bedingungswarteschlange befindet, wenn (zuerst! }} // Weck den Kopfknoten in der Bedingungswarteschlange private void Dosignal (Knoten zuerst) {do {// 1. Bewegen Sie den FirstWaiter -Referenz nacheinander nach einem if ((Firstwaiter = First.NextWaiter) == NULL) {lastWaiter = null; } // 2. Leeren Sie die Referenz des Nachfolgerknotens des Kopfknotens zuerst.NextWaiter = null; // 3. Übertragen Sie den Kopfknoten in die Synchronisationswarteschlange, und es ist möglich, den Thread nach Abschluss der Übertragung aufzuwecken // 4. Wenn die Operation von TransferForsignal fehlschlägt, wecken Sie den nächsten Knoten} while (! TransferForsignal (First) && (First = FirstWaiter)! Node.Condition, 0)) {// Wenn die Operation zur Aktualisierung des Status fehlschlägt, geben Sie Falsch direkt zurück // Es kann sein, dass die Methode von TransferAfterCancelledWait den Status zuerst geändert hat, wodurch dieser CAS -Vorgang fehlgeschlagen ist. } // Fügen Sie diesen Knoten zum Schwanz des Synchronisations -Warteschlangenknotens p = eNQ (Knoten) hinzu; int ws = p.waitstatus; if (ws> 0 ||! vergleicheSetwaitstatus (p, ws, node.signal)) {// Der aktuelle Thread wird geweckt, wenn die folgende Situation auftritt // 1. Der Vorwärtsknoten befindet sich im Stornierungsstatus // 2. Der Status des Aktualisierungsknotens ist Signaloperation fehlgeschlagen locksupport.unpark (node.thread); } return true;}Es ist ersichtlich, dass der ultimative Kern der Signalmethode darin besteht, die TransferForsignal -Methode aufzurufen. Verwenden Sie bei der Methode zur TransferForsignal -Methode zuerst den CAS -Betrieb, um den Zustand des Knotens von Bedingung auf 0 festzulegen, und rufen Sie dann die ENQ -Methode auf, um den Knoten zum Schwanz der Synchronisationswarteschlange hinzuzufügen. Wir sehen die nächste IF -Urteilsaussage. Diese Urteilsaussage wird hauptsächlich verwendet, um zu bestimmen, wann der Thread geweckt wird. Wenn diese beiden Situationen auftreten, wird der Faden sofort geweckt. Einer ist, wenn festgestellt wird, dass der Status des vorherigen Knotens abgesagt wird und der andere, wenn der Status des vorherigen Knotens nicht aktualisiert wird. Beide Fälle wecken den Thread sofort auf, andernfalls wird er durchgeführt, indem der Knoten einfach aus der bedingten Warteschlange in die Synchronisationswarteschlange übertragen wird und den Thread im Knoten nicht sofort aufweckt. Die Signalall -Methode ist ungefähr ähnlich, außer dass es alle Knoten in der bedingten Warteschlange durchschlägt und an die synchrone Warteschlange überträgt. Die Methode zum Übertragen von Knoten ruft die TransferForsignal -Methode weiter.
7. Wach alle Knoten der Bedingungswarteschlange auf
// Wach alle Knoten hinter der Bedingung auf, die öffentliche endgültige void signalall () {// beurteilen, ob der aktuelle Thread das Schloss hält if (! ISheldexclusiv ()) {Wirf neu illegalMonitorStateException (); } // Erhalten Sie den Bedingungs -Warteschlangen -Header -Knotenknoten first = FirstWaiter; if (zuerst! }} // Alle Knoten der Bedingungswarteschlange private void Dosignalall (Knoten zuerst) {// Zuerst die Referenzen des Header -Knotens und des Tail -Knotens lastWaiter = Firstwaiter = null leeren; DO {// Die Referenz des Nachfolgeknotens first = first.NextWaiter; // leeren Sie die nachfolgende Referenz des Knotens, die zuerst übertragen werden sollen. // Übertragen Sie den Knoten aus der bedingten Warteschlange in die Synchronisation Warteschlange TransferForsignal (zuerst); // Zeigen Sie den Verweis auf den nächsten Knoten zuerst = Weiter; } while (zuerst! = null);}Zu diesem Zeitpunkt ist unsere gesamte Quellcode -Analyse des AbstractQueuedsynchronizers vorbei. Ich glaube, dass jeder durch diese vier Analysen AQs besser beherrschen und verstehen kann. Diese Kategorie ist in der Tat sehr wichtig, da sie der Eckpfeiler vieler anderer Synchronisationskategorien ist. Aufgrund der begrenzten Niveau- und Expressionsfähigkeit des Autors, wenn es keine klaren Aussagen oder ein unzureichendes Verständnis gibt, korrigieren Sie sie rechtzeitig und diskutieren und lernen Sie zusammen. Sie können eine Nachricht hinterlassen, um das Problem unten zu lesen. Wenn Sie einen AQS -Kommentarquellcode benötigen, können Sie sich auch an den Autor wenden, um ihn anzufordern.
Hinweis: Alle oben genannten Analysen basieren auf JDK1.7, und es wird Unterschiede zwischen verschiedenen Versionen geben, die Leser müssen aufpassen.
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.