Ich habe einige Fragen zur Verwendung und Bedeutung des synchronized
Schlüsselworts.
- Welche Bedeutung hat das
synchronized
Schlüsselwort? - Wann sollten Methoden sein
synchronized
? - Was bedeutet es programmatisch und logisch?
java
multithreading
keyword
synchronized
Johanna
quelle
quelle
Antworten:
Das
synchronized
Schlüsselwort handelt von verschiedenen Threads, die in dieselben Variablen, Objekte und Ressourcen lesen und schreiben. Dies ist kein triviales Thema in Java, aber hier ist ein Zitat von Sun:Kurz gesagt: Wenn Sie zwei Threads haben, die in derselben 'Ressource' lesen und schreiben, beispielsweise eine Variable mit dem Namen
foo
, müssen Sie sicherstellen, dass diese Threads auf atomare Weise auf die Variable zugreifen. Ohne dassynchronized
Schlüsselwort sieht Ihr Thread 1 möglicherweise nicht, dass der Änderungsthread 2 vorgenommen wurdefoo
, oder schlimmer noch, er wird möglicherweise nur zur Hälfte geändert. Dies ist nicht das, was Sie logischerweise erwarten.Auch dies ist in Java ein nicht triviales Thema. Weitere Informationen finden Sie hier auf SO und in den Interwebs zu folgenden Themen:
Erforschen Sie diese Themen so lange, bis der Name "Brian Goetz" dauerhaft mit dem Begriff "Parallelität" in Ihrem Gehirn in Verbindung gebracht wird.
quelle
Nun, ich denke, wir hatten genug theoretische Erklärungen, also denken Sie an diesen Code
Hinweis:
synchronized
Blockiert den Aufruf des nächsten Threads an method test (), solange die Ausführung des vorherigen Threads nicht abgeschlossen ist. Threads können einzeln auf diese Methode zugreifen. Ohnesynchronized
alle Threads kann gleichzeitig auf diese Methode zugegriffen werden.Wenn ein Thread die synchronisierte Methode 'test' des Objekts aufruft (hier ist das Objekt eine Instanz der 'TheDemo'-Klasse), erhält er die Sperre dieses Objekts. Ein neuer Thread kann KEINE synchronisierte Methode desselben Objekts aufrufen, solange der vorherige Thread Wer das Schloss erworben hat, gibt das Schloss nicht frei.
Ähnliches passiert, wenn eine statisch synchronisierte Methode der Klasse aufgerufen wird. Der Thread erhält die der Klasse zugeordnete Sperre (in diesem Fall kann jede nicht statische synchronisierte Methode einer Instanz dieser Klasse von jedem Thread aufgerufen werden, da diese Sperre auf Objektebene noch verfügbar ist). Ein anderer Thread kann keine statisch synchronisierte Methode der Klasse aufrufen, solange die Sperre auf Klassenebene nicht von dem Thread freigegeben wird, der derzeit die Sperre enthält.
Ausgabe mit synchronisiert
Ausgabe ohne synchronisiert
quelle
synchronized
, aber die Speicherkonsistenz wird ignoriert.Das
synchronized
Schlüsselwort verhindert den gleichzeitigen Zugriff mehrerer Threads auf einen Code- oder Objektblock. Alle Methoden vonHashtable
aresynchronized
sind so, dass jeweils nur ein Thread sie ausführen kann.Wenn Sie Nicht-
synchronized
Konstrukte wie verwendenHashMap
, müssen Sie Thread-Sicherheitsfunktionen in Ihrem Code erstellen, um Konsistenzfehler zu vermeiden.quelle
synchronized
bedeutet, dass in einer Umgebung mit mehreren Threads ein Objekt mitsynchronized
Methode (n) / Block (en) nicht zwei Threads gleichzeitig auf diesynchronized
Methode (n) / Block (e) des Codes zugreifen lässt . Dies bedeutet, dass ein Thread nicht lesen kann, während ein anderer Thread ihn aktualisiert.Der zweite Thread wartet stattdessen, bis der erste Thread seine Ausführung abgeschlossen hat. Der Overhead ist die Geschwindigkeit, aber der Vorteil ist die garantierte Datenkonsistenz.
Wenn Ihre Anwendung jedoch Single-Threaded ist,
synchronized
bieten Blöcke keine Vorteile.quelle
Das
synchronized
Schlüsselwort bewirkt, dass ein Thread bei der Eingabe der Methode eine Sperre erhält, sodass nur ein Thread die Methode gleichzeitig ausführen kann (für die angegebene Objektinstanz, sofern es sich nicht um eine statische Methode handelt).Dies wird häufig als Thread-sicher bezeichnet, aber ich würde sagen, dass dies ein Euphemismus ist. Zwar schützt die Synchronisierung den internen Status des Vektors vor Beschädigung, dies hilft dem Benutzer von Vector jedoch normalerweise nicht viel.
Bedenken Sie:
Obwohl die beteiligten Methoden synchronisiert sind, weil sie einzeln gesperrt und entsperrt werden, können zwei leider zeitgesteuerte Threads einen Vektor mit zwei Elementen erstellen.
Tatsächlich müssen Sie also auch Ihren Anwendungscode synchronisieren.
Da die Synchronisation auf Methodenebene a) teuer ist, wenn Sie sie nicht benötigen, und b) unzureichend ist, wenn Sie eine Synchronisation benötigen, gibt es jetzt nicht synchronisierte Ersetzungen (ArrayList im Fall von Vector).
In jüngerer Zeit wurde das Parallelitätspaket mit einer Reihe cleverer Dienstprogramme veröffentlicht, die sich um Multithreading-Probleme kümmern.
quelle
Überblick
Das synchronisierte Schlüsselwort in Java hat mit der Thread-Sicherheit zu tun, dh wenn mehrere Threads dieselbe Variable lesen oder schreiben.
Dies kann direkt (durch Zugriff auf dieselbe Variable) oder indirekt (durch Verwendung einer Klasse, die eine andere Klasse verwendet, die auf dieselbe Variable zugreift) geschehen.
Das synchronisierte Schlüsselwort wird verwendet, um einen Codeblock zu definieren, in dem mehrere Threads auf sichere Weise auf dieselbe Variable zugreifen können.
Tiefer
In Bezug auf die Syntax
synchronized
nimmt das Schlüsselwort aObject
als Parameter (als Sperrobjekt bezeichnet ) an, gefolgt von a{ block of code }
.Wenn die Ausführung dieses Schlüsselwort trifft, der aktuelle Thread versucht, „lock / acquire / eigenen“ (nehmen Sie Ihre Wahl) , um das Sperrobjekt hat und führen Sie den zugehörigen Code - Block , nachdem die Sperre erworben.
Alle Schreibvorgänge in Variablen innerhalb des synchronisierten Codeblocks sind garantiert für jeden anderen Thread sichtbar, der Code in einem synchronisierten Codeblock mit demselben Sperrobjekt auf ähnliche Weise ausführt .
Es kann jeweils nur ein Thread die Sperre halten. Während dieser Zeit warten alle anderen Threads, die versuchen, dasselbe Sperrobjekt zu erhalten , (halten ihre Ausführung an). Die Sperre wird aufgehoben, wenn die Ausführung den synchronisierten Codeblock verlässt.
Synchronisierte Methoden:
Hinzufügen
synchronized
Schlüsselwort zu einer Methodendefinition ist gleich den gesamte Verfahren Körper in einem synchronisierten Codeblock mit eingewickelt Sperrobjekt Wesenthis
(beispielsweise Methoden) undClassInQuestion.getClass()
(für Klassenmethoden) .- Die Instanzmethode ist eine Methode ohne
static
Schlüsselwort.- Die Klassenmethode ist eine Methode mit einem
static
Schlüsselwort.Technisch
Ohne Synchronisation kann nicht garantiert werden, in welcher Reihenfolge die Lese- und Schreibvorgänge stattfinden, wodurch möglicherweise die Variable mit Müll belassen wird.
(Zum Beispiel könnte eine Variable die Hälfte der von einem Thread geschriebenen Bits und die Hälfte der von einem anderen Thread geschriebenen Bits enthalten, wodurch die Variable in einem Zustand verbleibt, den keiner der Threads zu schreiben versucht hat, sondern ein kombiniertes Durcheinander von beiden.)
Es reicht nicht aus, einen Schreibvorgang in einem Thread abzuschließen, bevor (Wanduhrzeit) ein anderer Thread ihn liest, da die Hardware den Wert der Variablen zwischengespeichert haben könnte und der Lesethread den zwischengespeicherten Wert anstelle dessen sehen würde, in den geschrieben wurde es.
Fazit
In Javas Fall müssen Sie daher dem Java-Speichermodell folgen, um sicherzustellen, dass keine Threading-Fehler auftreten.
Mit anderen Worten: Verwenden Sie Synchronisation, atomare Operationen oder Klassen, die sie für Sie unter der Haube verwenden.
quelle
Stellen Sie sich das als eine Art Drehkreuz vor, wie Sie es auf einem Fußballplatz finden könnten. Es gibt parallele Dämpfe von Menschen, die einsteigen wollen, aber am Drehkreuz sind sie "synchronisiert". Es kann immer nur eine Person durchkommen. Alle, die durchkommen wollen, werden es tun, aber sie müssen möglicherweise warten, bis sie durchkommen können.
quelle
Threads kommunizieren hauptsächlich durch gemeinsame Nutzung des Zugriffs auf Felder und die Objekte, auf die sich Referenzfelder beziehen. Diese Form der Kommunikation ist äußerst effizient, ermöglicht jedoch zwei Arten von Fehlern: Thread-Interferenz und Speicherkonsistenzfehler . Das zur Vermeidung dieser Fehler erforderliche Tool ist die Synchronisation.
Synchronisierte Blöcke oder Methoden verhindern Thread-Interferenzen und stellen sicher, dass die Daten konsistent sind. Zu jedem Zeitpunkt kann nur ein Thread auf einen synchronisierten Block oder eine synchronisierte Methode ( kritischer Abschnitt ) zugreifen, indem er eine Sperre erwirbt. Andere Threads warten auf die Freigabe der Sperre, um auf den kritischen Abschnitt zuzugreifen .
Methoden werden synchronisiert, wenn Sie sie
synchronized
zur Methodendefinition oder -deklaration hinzufügen . Sie können einen bestimmten Codeblock auch mit einer Methode synchronisieren.Dies bedeutet, dass nur ein Thread durch Erwerb einer Sperre auf einen kritischen Abschnitt zugreifen kann . Sofern dieser Thread diese Sperre nicht aufhebt, müssen alle anderen Threads warten, um eine Sperre zu erhalten. Sie haben keinen Zugriff auf den kritischen Bereich , ohne eine Sperre zu erhalten.
Dies kann nicht mit Magie geschehen. Es liegt in der Verantwortung des Programmierers, kritische Abschnitte in der Anwendung zu identifizieren und entsprechend zu schützen. Java bietet ein Framework zum Schutz Ihrer Anwendung, aber wo und was alle zu schützenden Abschnitte sind, liegt in der Verantwortung des Programmierers.
Weitere Details von Java - Dokumentation Seite
Eigensperren und Synchronisation:
Jedem Objekt ist eine intrinsische Sperre zugeordnet . Gemäß der Konvention muss ein Thread, der exklusiven und konsistenten Zugriff auf die Felder eines Objekts benötigt, die intrinsische Sperre des Objekts abrufen, bevor er auf sie zugreift, und dann die intrinsische Sperre aufheben, wenn sie damit fertig ist.
Ein Thread soll die intrinsische Sperre zwischen dem Zeitpunkt, zu dem er die Sperre erworben und die Sperre freigegeben hat, besitzen. Solange ein Thread eine intrinsische Sperre besitzt, kann kein anderer Thread dieselbe Sperre erhalten. Der andere Thread wird blockiert, wenn er versucht, die Sperre zu erlangen.
Das Synchronisieren von Methoden hat zwei Auswirkungen :
Wenn ein Thread eine synchronisierte Methode für ein Objekt ausführt, blockieren alle anderen Threads, die synchronisierte Methoden für denselben Objektblock aufrufen (Ausführung aussetzen), bis der erste Thread mit dem Objekt fertig ist.
Dies garantiert, dass Änderungen am Status des Objekts für alle Threads sichtbar sind.
Suchen Sie nach anderen Alternativen zur Synchronisation in:
Vermeiden Sie (dies) in Java synchronisiert?
quelle
Synchronized normal method
äquivalent zuSynchronized statement
(benutze dies)Synchronized static method
äquivalent zuSynchronized statement
(Klasse verwenden)Synchronisierte Anweisung (unter Verwendung einer Variablen)
Denn
synchronized
wir haben beideSynchronized Methods
undSynchronized Statements
. IstSynchronized Methods
jedoch ähnlich,Synchronized Statements
so müssen wir nur verstehenSynchronized Statements
.=> Grundsätzlich werden wir haben
Hier sind 2 Gedanken, die zum Verständnis beitragen
synchronized
intrinsic lock
zugeordnet.synchronized statement
, erfasst er automatisch dasintrinsic lock
für diesessynchronized statement's
Objekt und gibt es frei, wenn die Methode zurückkehrt. Solange ein Thread einen besitztintrinsic lock
, kann KEIN anderer Thread die gleiche Sperre erhalten => threadsicher.=> Wenn ein
thread A
Aufrufsynchronized(this){// code 1}
=> ist der gesamte Blockcode (innerhalb der Klasse) wosynchronized(this)
und allesynchronized normal method
(innerhalb der Klasse) wegen der gleichen Sperre gesperrt . Es wird nach demthread A
Entsperren ausgeführt ("// Code 1" beendet).Dieses Verhalten ähnelt
synchronized(a variable){// code 1}
odersynchronized(class)
.SAME LOCK => lock (nicht abhängig von welcher Methode? Oder welchen Anweisungen?)
Synchronisierte Methode oder synchronisierte Anweisungen verwenden?
Ich bevorzuge,
synchronized statements
weil es erweiterbarer ist. In Zukunft müssen Sie beispielsweise nur einen Teil der Methode synchronisieren. Beispiel: Sie haben zwei synchronisierte Methoden, die für einander nicht relevant sind. Wenn ein Thread jedoch eine Methode ausführt, blockiert er die andere Methode (dies kann durch Verwendung verhindert werdensynchronized(a variable)
).Das Anwenden der synchronisierten Methode ist jedoch einfach und der Code sieht einfach aus. Für einige Klassen gibt es nur eine synchronisierte Methode oder alle synchronisierten Methoden in der Klasse, die für einander relevant sind => Wir können
synchronized method
den Code kürzer und verständlicher machenHinweis
(es ist nicht zu relevant für viel
synchronized
, es ist der Unterschied zwischen Objekt und Klasse oder nicht statisch und statisch).synchronized
oder normale Methode odersynchronized(this)
odersynchronized(non-static variable)
Base auf jeder Objektinstanz wird es synchronisiert.synchronized
statische Methode verwenden odersynchronized(class)
odersynchronized(static variable)
sie wird basierend auf der Klasse synchronisiertReferenz
https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
Hoffe es hilft
quelle
Hier ist eine Erklärung aus den Java-Tutorials .
Betrachten Sie den folgenden Code:
quelle
Nach meinem Verständnis bedeutet synchronisiert im Grunde, dass der Compiler eine monitor.enter und eine monitor.exit um Ihre Methode schreibt. Als solches kann es threadsicher sein, abhängig davon, wie es verwendet wird (ich meine, Sie können ein Objekt mit synchronisierten Methoden schreiben, das nicht threadsicher ist, abhängig davon, was Ihre Klasse tut).
quelle
Was den anderen Antworten fehlt, ist ein wichtiger Aspekt: Gedächtnisbarrieren . Die Thread-Synchronisation besteht im Wesentlichen aus zwei Teilen: Serialisierung und Sichtbarkeit. Ich rate jedem, nach "jvm memory barriere" zu googeln, da dies ein nicht triviales und äußerst wichtiges Thema ist (wenn Sie gemeinsam genutzte Daten ändern, auf die mehrere Threads zugreifen). Nachdem dies geschehen ist, empfehle ich, die Klassen des Pakets java.util.concurrent zu betrachten, um die Verwendung einer expliziten Synchronisierung zu vermeiden, was wiederum dazu beiträgt, Programme einfach und effizient zu halten und möglicherweise sogar Deadlocks zu verhindern.
Ein solches Beispiel ist ConcurrentLinkedDeque . Zusammen mit dem Befehlsmuster können hocheffiziente Arbeitsthreads erstellt werden, indem die Befehle in die gleichzeitige Warteschlange eingefügt werden - keine explizite Synchronisierung erforderlich, keine Deadlocks möglich, kein expliziter sleep () erforderlich, einfach die Warteschlange durch Aufrufen von take () abfragen.
Kurz gesagt: "Speichersynchronisation" geschieht implizit, wenn Sie einen Thread starten, ein Thread endet, Sie eine flüchtige Variable lesen, einen Monitor entsperren (einen synchronisierten Block / eine synchronisierte Funktion verlassen) usw. Diese "Synchronisation" wirkt sich (in gewissem Sinne "auf" Flushes "aus ") alle Schreibvorgänge, die vor dieser bestimmten Aktion ausgeführt wurden. Im Fall der oben genannten ConcurrentLinkedDeque "sagt" die Dokumentation:
Dieses implizite Verhalten ist ein etwas schädlicher Aspekt, da die meisten Java-Programmierer ohne viel Erfahrung aufgrund dessen nur eine Menge nehmen, wie angegeben. Und dann stolpern Sie plötzlich über diesen Thread, nachdem Java nicht das getan hat, was es in der Produktion "tun" soll, wo es eine andere Arbeitslast gibt - und es ziemlich schwierig ist, Parallelitätsprobleme zu testen.
quelle
Synchronisiert bedeutet einfach, dass mehrere Threads, wenn sie einem einzelnen Objekt zugeordnet sind, ein fehlerhaftes Lesen und Schreiben verhindern können, wenn für ein bestimmtes Objekt ein synchronisierter Block verwendet wird. Um Ihnen mehr Klarheit zu geben, nehmen wir ein Beispiel:
Wir haben zwei MyRunnable-Klassenobjekte erstellt: runnable1 wird für Thread 1 und Thread 3 freigegeben, und runnable2 wird nur für Thread 2 freigegeben. Wenn nun t1 und t3 ohne Synchronisation gestartet werden, wird eine PFB-Ausgabe ausgegeben, die darauf hindeutet, dass beide Threads 1 und 3 gleichzeitig den var-Wert beeinflussen, wobei var für Thread 2 einen eigenen Speicher hat.
Bei Verwendung von Synchronzied wartet Thread 3 in allen Szenarien darauf, dass Thread 1 abgeschlossen ist. Es wurden zwei Sperren erworben, eine für runnable1, die von Thread 1 und Thread 3 gemeinsam genutzt wird, und eine für runnable2, die nur von Thread 2 gemeinsam genutzt wird.
quelle
Einfach synchronisiert bedeutet, dass keine zwei Threads gleichzeitig auf den Block / die Methode zugreifen können. Wenn wir sagen, dass ein Block / eine Methode einer Klasse synchronisiert ist, bedeutet dies, dass jeweils nur ein Thread auf sie zugreifen kann. Intern nimmt der Thread, der zuerst versucht, darauf zuzugreifen, eine Sperre für dieses Objekt auf. Solange diese Sperre nicht verfügbar ist, kann kein anderer Thread auf eine der synchronisierten Methoden / Blöcke dieser Instanz der Klasse zugreifen.
Beachten Sie, dass ein anderer Thread auf eine Methode desselben Objekts zugreifen kann, die nicht für die Synchronisierung definiert ist. Ein Thread kann die Sperre durch Aufrufen aufheben
quelle
synchronized
Block in Java ist ein Monitor im Multithreading.synchronized
Block mit demselben Objekt / derselben Klasse kann nur von einem einzelnen Thread ausgeführt werden, alle anderen warten. Dies kann hilfreich seinrace condition
, wenn mehrere Threads versuchen, dieselbe Variable zu aktualisieren (der erste Schritt ist die Verwendung vonvolatile
Info ).Java 5
erweitertsynchronized
durch die Unterstützung vonhappens-before
[About]Der nächste Schritt ist
java.util.concurrent
flüchtig vs synchronisiert
quelle
synchronisiert ist ein Schlüsselwort in Java, das verwendet wird, um vor einer Beziehung in einer Multithreading-Umgebung zu geschehen, um Speicherinkonsistenzen und Thread-Interferenzfehler zu vermeiden.
quelle