Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Vorwort

 Jeder sollte mit Synchronized und  ReentrantLock vertraut sein . Als die am häufigsten verwendete lokale Sperre in Java ist die Leistung von ReentrantLock in der ursprünglichen Version viel besser als die von Synchronized. Nachfolgendes Java hat viele Optimierungen an Synchronized in Iterationen von Versionen vorgenommen. Bis jdk1.6 ist die Leistung der beiden Sperren nahezu gleich, und selbst die synchronisierte automatische Freigabesperre ist nützlicher.

Bei der Frage nach der Wahl von Synchronized und ReentrantLock während des Interviews platzten viele Freunde heraus, dass mit Synchronized nur sehr wenige Menschen antworten konnten, selbst wenn ich den Interviewer während des Interviews fragte. Moon wollte sagen, dass dies nicht unbedingt der Fall ist.  Studenten, die sich nur für den Titel interessieren, können direkt bis zum Ende gehen  , ich bin keine Titelparty ~

Synchronisierte Verwendung

Die Verwendung von in Java synchronisiertem Code   ist sehr einfach

  • 1. Fügen Sie direkt in die Methode ein (die Bytecode-Datei der aktuellen Klasse ist gesperrt).
  • 2. Fügen Sie den Codeblock ein (das Objekt ist gesperrt).

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Was passiert mit dem synchronisierten Code, während das Programm ausgeführt wird?

Schau dir ein Bild an

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Beim Ausführen von Multithreads greift der  Thread zuerst auf den Monitor des Objekts zu  . Dieser Monitor ist für das Objekt eindeutig. Er entspricht einem Schlüssel. Wenn Sie ihn greifen, haben Sie das Recht, den aktuellen auszuführen Codeblock.

Andere Threads, die nicht erfasst wurden, werden in die Warteschlange (SynchronizedQueue) gestellt und warten, bis der aktuelle Thread ausgeführt wurde. Lassen Sie die Sperre aufheben.

Nachdem der aktuelle Thread ausgeführt wurde, wird er benachrichtigt, die Warteschlange zu verlassen und den aktuellen Vorgang weiter zu wiederholen.

Aus Sicht von JVM repräsentieren die Anweisungen für Monitorenter und Monitorexit die Ausführung und das Ende des Codes.

SynchronizedQueue:

SynchronizedQueue ist eine spezielle Warteschlange. Sie hat keine Speicherfunktion. Sie dient zum Verwalten einer Reihe von Threads. Jeder Einfügevorgang muss auf den Entfernungsvorgang eines anderen Threads warten. Ebenso wartet jeder Entfernungsvorgang auf das Einfügen eines anderen Threads. Daher befindet sich in dieser Warteschlange tatsächlich kein Element, oder die Kapazität ist 0, was nicht unbedingt ein Container ist. Da die Warteschlange keine Kapazität hat, kann die Peek-Operation nicht aufgerufen werden, da nur Elemente vorhanden sind, wenn sie entfernt werden.

zum Beispiel:

Gießen Sie beim Trinken  zuerst den Wein in die Weinschale und dann in das Weinglas. Dies ist eine normale Warteschlange  .

Gießen Sie beim Trinken  den Wein direkt in das Glas, dies ist die SynchronizedQueue  .

Dieses Beispiel sollte sehr klar und leicht verständlich sein. Der Vorteil besteht darin, dass es direkt geliefert werden kann, sodass kein Lieferprozess durch Dritte erforderlich ist.

Sprechen Sie über die Details und den Vorgang des Sperren-Upgrades

Vor jdk1.6 ist Synchronized eine Schwergewichts-Sperre, oder veröffentlichen Sie zuerst ein Bild

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Aus diesem Grund ist Synchronized eine Schwergewichts-Sperre, da jede Sperrressource direkt mit der CPU angewendet wird und die Anzahl der CPU-Sperren festgelegt ist. Wenn die CPU-Sperrressource aufgebraucht ist, wartet sie auf die Sperre zeitaufwändige Bedienung.

In jdk1.6 werden jedoch viele Optimierungen auf Codeebene vorgenommen, was wir häufig als Prozess des Sperren-Upgrades bezeichnen.

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Dies ist  der Prozess des Sperren-Upgrades  . Lassen Sie uns kurz darüber sprechen:

  • Keine Sperre: Das Objekt wird von Anfang an entsperrt.
  • Teilsperre: Dies  entspricht dem  Anhängen einer Beschriftung an das Objekt (speichern Sie Ihre Thread-ID im Objektheader). Wenn ich das nächste Mal hereinkomme, stelle ich fest, dass die Beschriftung mir gehört, damit ich sie weiterhin verwenden kann.
  • Spin Lock: Stellen Sie sich eine Toilette mit einer Person vor. Sie möchten gehen, aber es gibt nur eine Grube, sodass Sie nur wandern und warten können. Sie können sie benutzen, wenn diese Person herauskommt. Bei diesem Spin wird cas verwendet, um die Atomizität sicherzustellen. Ich werde hier nicht auf Details zu cas eingehen.
  • Schwergewichts-Sperren:  Beantragen Sie Sperren direkt von der CPU  , und andere Threads warten in der Warteschlange.

Wann fand die Sperreneskalation statt?

  • Voreingenommene Sperre: Wenn ein Thread eine Sperre erhält, wird diese von einer sperrenfreien auf eine voreingenommene Sperre aktualisiert
  • Spin Lock: Wenn die Thread-Konkurrenz auftritt, wird die Bias Lock auf die Spin Lock aktualisiert. Stellen Sie sich vor, while (true);
  • Schwergewichtsschloss: Wenn der Fadenwettbewerb eine bestimmte Anzahl erreicht oder eine bestimmte Zeit überschreitet, wird er zu einem Schwergewichtsschloss befördert

Wo werden die Sperrinformationen aufgezeichnet?

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Dieses Bild ist die Datenstruktur des Markierungsworts im Objektkopf  . Hier werden die Sperrinformationen gespeichert, die die Änderung der Sperrinformationen beim  Upgrade der Sperre deutlich zeigen. Tatsächlich wird das Objekt durch einen Binärwert markiert. Jeder Wert repräsentiert einen Staat.

Gibt es ein Sperr-Downgrade, da synchronized ein Sperren-Upgrade hat?

Diese Frage hat viel mit unserem Thema zu tun.

In der virtuellen HotSpot-Maschine tritt eine Verschlechterung der Sperre auf, die  jedoch nur in STW auftritt,  und nur der Garbage Collection-Thread kann dies beobachten. Das heißt, während unserer normalen Verwendung tritt keine Verschlechterung der Sperre auf. Sie wird nur während der GC herabgestuft.

Also die Antwort auf die Frage, verstehst du? Haha, lass uns runter gehen.

Verwendung von ReentrantLock

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Die Verwendung von ReentrantLock ist ebenfalls sehr einfach. Der Unterschied zu Synchronized besteht darin, dass Sie die Sperre manuell aufheben müssen. Um eine bestimmte Freigabe sicherzustellen, wird sie normalerweise in Verbindung mit try ~ finally verwendet.

Prinzip von ReentrantLock

ReentrantLock bedeutet Reentrant  Lock  . Wenn es um ReentrantLock geht, müssen Sie AQS sagen, da die  zugrunde liegende Ebene mit AQS  implementiert wird .

ReentrantLock verfügt über  zwei Modi  , einen fairen und einen unfairen Modus .

  • Im fairen Modus werden wartende Threads in strikter Übereinstimmung mit der Warteschlangenreihenfolge ausgeführt, nachdem sie in die Warteschlange gestellt wurden
  • Im unfairen Modus kann es zu einem Warteschlangensprung kommen, nachdem darauf gewartet wurde, dass ein Thread in die Warteschlange eintritt

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Dies ist das Strukturdiagramm von ReentrantLock. Wir sehen uns dieses Bild tatsächlich sehr einfach an, da die Hauptimplementierung AQS überlassen bleibt. Konzentrieren wir uns auf AQS.

AQS

AQS (AbstractQueuedSynchronizer): AQS kann als Framework verstanden werdendas Sperren implementieren kann  .

Einfaches Prozessverständnis:

Faires Schloss:

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

  • Schritt 1: Ermitteln Sie den Wert von state. Wenn state = 0 ist, bedeutet dies, dass die Sperre nicht von anderen Threads belegt ist und der zweite Schritt ausgeführt wird. Wenn state! = 0 ist, bedeutet dies, dass die Sperre von anderen Threads belegt wird und der dritte Schritt ausgeführt wird.
  • Schritt 2: Stellen Sie fest, ob Threads in der Warteschlange warten. Wenn es nicht vorhanden ist, wird der Eigentümer der Sperre direkt auf den aktuellen Thread gesetzt und der Status aktualisiert. Treten Sie dem Team bei, falls vorhanden.
  • Schritt 3: Stellen Sie fest, ob der Eigentümer der Sperre der aktuelle Thread ist. Wenn ja, aktualisieren Sie den Statuswert. Wenn nicht, tritt der Thread in die Warteschlange ein und wartet.

Unfaire Sperre:

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

  • Schritt 1: Ermitteln Sie den Wert von state. Wenn state = 0 bedeutet, dass die Sperre nicht von anderen Threads belegt ist, wird der aktuelle Sperrhalter auf den aktuellen Thread gesetzt und der Vorgang mit CAS abgeschlossen. Wenn es nicht 0 ist oder die Einstellung fehlschlägt, bedeutet dies, dass die Sperre belegt ist und Sie mit dem nächsten Schritt fortfahren.
  • Ermitteln Sie zu diesem Zeitpunkt den Statuswert. Wenn er 0 ist, bedeutet dies, dass der Thread die Sperre gerade freigegeben hat. Stellen Sie zu diesem Zeitpunkt den Schlosshalter auf sich selbst ein. Wenn er nicht 0 ist, überprüfen Sie, ob der Threadhalter selbst ist Geben Sie also den Status + 1 ein. Wenn die Sperre nicht erreicht wurde, treten Sie in die Warteschlange ein und warten Sie

Nachdem Sie den obigen Teil gelesen haben, haben Sie meines Erachtens ein klareres Konzept für AQS. Lassen Sie uns also über die kleinen Details sprechen.

AQS verwendet den Status-Synchronisationsstatus (0 bedeutet keine Sperre, 1 bedeutet ja) und macht die Operationen getState, setState und compareAndSet verfügbar, um diesen Status zu lesen und zu aktualisieren, sodass er nur atomar festgelegt wird, wenn der Synchronisierungsstatus einen erwarteten Wert hat In den neuen Wert.

Wenn ein Thread die Sperre nicht erhält,  schließt AQS die Verwaltung des Synchronisationsstatus über eine  bidirektionale Synchronisationswarteschlange ab und wird am Ende der Warteschlange hinzugefügt.

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Dies ist der Code, der die Kopf- und Endknoten definiert. Wir können ihn zuerst  mit volatile ändern um sicherzustellen, dass andere Threads sichtbar sind. AQS ändert tatsächlich die Kopf- und Endknoten, um die Enqueue- und Dequeue-Operationen abzuschließen.

Wenn AQS eine Sperre erwirbt, muss nicht nur ein Thread die Sperre halten   . Daher besteht derzeit ein Unterschied zwischen dem exklusiven Modus und dem freigegebenen Modus . Das ReentrantLock in diesem Artikel   verwendet den exklusiven Modus nur für mehrere Threads Ein Thread erhält die Sperre.

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Der Vorgang des Exklusivmodus ist relativ einfach. Es wird beurteilt, ob ein Thread die Sperre erhalten hat, je nachdem, ob der Status 0 ist. Wenn er blockiert ist, führt er die nachfolgende Codelogik weiter aus.

Warum wird bei dynamisch hoher Parallelität eine Wiedereintrittssperre anstelle einer Synchronisierung empfohlen?

Der Prozess im gemeinsam genutzten Modus beurteilt, ob ein Thread die Sperre erhalten hat, je nachdem, ob der Status größer als 0 ist. Wenn er nicht größer als 0 ist, wird er blockiert. Wenn er größer als 0 ist, wird der Statuswert durch den Wert subtrahiert atomare Operation von CAS, und fahren Sie dann fort, die nachfolgende Codelogik auszuführen.

Der Unterschied zwischen ReentrantLock und Synchronized

  • Tatsächlich besteht der Hauptunterschied zwischen ReentrantLock und Synchronized  darin, dass  Synchronized für einen Wettbewerb mit geringer Parallelität geeignet ist. Wenn das Sperren-Upgrade von Synchronized schließlich auf ein Schwergewichts-Schloss aktualisiert wird, gibt es keine Möglichkeit, es während der Verwendung zu beseitigen, was bedeutet, dass dies erforderlich ist Jedes Mal mit der CPU kombinieren Um Sperrressourcen anzufordern, bietet ReentrantLock hauptsächlich die Möglichkeit zum Blockieren.  Durch das Aussetzen von Threads bei hoher Parallelität kann der Wettbewerb verringert und die Parallelität verbessert werden  , sodass die Antwort auf den Titel unseres Artikels offensichtlich ist.
  • Synchronisiert ist ein Schlüsselwort, das von der JVM-Ebene  implementiert wird  , während ReentrantLock von der Java-API  implementiert wird  .
  • Synchronisiert ist eine implizite Sperre, die die Sperre automatisch  aufheben kann  , und ReentrantLock ist eine explizite Sperre, die eine manuelle Freigabe der Sperre erfordert   .
  • Mit ReentrantLock kann der Thread, der darauf wartet, dass die Sperre auf den Interrupt reagiert, aber synchronisiert funktioniert nicht. Bei Verwendung von synchronisiert wartet der wartende Thread für immer und  kann nicht auf den Interrupt reagieren.
  • ReentrantLock kann den Sperrstatus erhalten, synchronisiert jedoch nicht.

Sprechen Sie über die Antwort auf den Titel

Tatsächlich befindet sich die Antwort auf die Frage im ersten Punkt der vorherigen Spalte, der auch den Kernunterschied darstellt. Nachdem das synchronisierte Upgrade auf ein Schwergewichtsschloss durchgeführt wurde, kann das Downgrade unter normalen Umständen nicht abgeschlossen werden, während ReentrantLock die Leistung durch Blockieren verbessert. Dies spiegelt sich im Entwurfsmodus wider. Unterstützung für Situationen mit mehreren Threads hinzugefügt.

Ich denke du magst

Origin blog.csdn.net/doubututou/article/details/111046828
Empfohlen
Rangfolge