Kann mir jemand anhand eines Beispiels den Vorteil einer synchronisierten Methode gegenüber einem synchronisierten Block erklären?
401
Kann mir jemand anhand eines Beispiels den Vorteil einer synchronisierten Methode gegenüber einem synchronisierten Block erklären?
Antworten:
Es gibt keinen klaren Vorteil der Verwendung einer synchronisierten Methode gegenüber dem Block.
Vielleicht ist der einzige (aber ich würde es nicht als Vorteil bezeichnen), dass Sie die Objektreferenz nicht einschließen müssen
this
.Methode:
Block:
Sehen? Überhaupt kein Vorteil.
Blöcke haben jedoch Vorteile gegenüber Methoden, vor allem in Bezug auf die Flexibilität, da Sie ein anderes Objekt als Sperre verwenden können, während die Synchronisierung der Methode das gesamte Objekt sperren würde.
Vergleichen Sie:
vs.
Auch wenn die Methode wächst, können Sie den synchronisierten Abschnitt weiterhin getrennt halten:
quelle
synchronized
Block wird mit zwei Befehlen implementiert,monitorenter
undmonitorexit
, sowie ein Ausnahmebehandlungsroutine , die gewährleistet , dassmonitorexit
sogar in dem Ausnahmefall genannt. Das ist alles gespeichert, wenn einesynchronized
Methode verwendet wird.Der einzige wirkliche Unterschied besteht darin, dass ein synchronisierter Block auswählen kann, auf welchem Objekt er synchronisiert. Eine synchronisierte Methode kann nur
'this'
(oder die entsprechende Klasseninstanz für eine synchronisierte Klassenmethode) verwenden. Diese sind beispielsweise semantisch äquivalent:Letzteres ist flexibler, da es um die zugehörige Sperre eines beliebigen Objekts, häufig einer Mitgliedsvariablen, konkurrieren kann . Es ist auch detaillierter, da vor und nach dem Block möglicherweise gleichzeitig Code ausgeführt wird, der sich jedoch noch in der Methode befindet. Natürlich können Sie eine synchronisierte Methode genauso einfach verwenden, indem Sie den gleichzeitigen Code in separate nicht synchronisierte Methoden umgestalten. Verwenden Sie, was den Code verständlicher macht.
quelle
Synchronisierte Methode
Vorteile:
Nachteile:
Synchronisierter Block
Vorteile:
Nachteile:
Persönlich bevorzuge ich synchronisierte Methoden mit Klassen, die sich nur auf das konzentrieren, was synchronisiert werden muss. Eine solche Klasse sollte so klein wie möglich sein und daher sollte es einfach sein, die Synchronisation zu überprüfen. Andere sollten sich nicht um die Synchronisation kümmern müssen.
quelle
Der Hauptunterschied besteht darin, dass Sie bei Verwendung eines synchronisierten Blocks möglicherweise ein anderes Objekt als dieses sperren , wodurch Sie viel flexibler werden können.
Angenommen, Sie haben eine Nachrichtenwarteschlange und mehrere Nachrichtenproduzenten und -konsumenten. Wir möchten nicht, dass sich die Produzenten gegenseitig stören, aber die Verbraucher sollten in der Lage sein, Nachrichten abzurufen, ohne auf die Produzenten warten zu müssen. Also erstellen wir einfach ein Objekt
Und von nun an setzen wir jedes Mal, wenn ein Produzent eine neue Nachricht hinzufügen möchte, einfach darauf:
So können Verbraucher noch lesen, und Produzenten werden gesperrt.
quelle
Synchronisierte Methode
Synchronisierte Methoden haben zwei Auswirkungen.
Wenn ein Thread eine synchronisierte Methode für ein Objekt ausführt, blockieren zunächst alle anderen Threads, die synchronisierte Methoden für denselben Objektblock aufrufen (Ausführung aussetzen), bis der erste Thread mit dem Objekt fertig ist.
Zweitens wird beim Beenden einer synchronisierten Methode automatisch eine Vorher-Beziehung zu einem nachfolgenden Aufruf einer synchronisierten Methode für dasselbe Objekt hergestellt. Dies garantiert, dass Änderungen am Status des Objekts für alle Threads sichtbar sind.
Beachten Sie, dass Konstruktoren nicht synchronisiert werden können. Die Verwendung des synchronisierten Schlüsselworts mit einem Konstruktor ist ein Syntaxfehler. Das Synchronisieren von Konstruktoren ist nicht sinnvoll, da nur der Thread, der ein Objekt erstellt, während der Erstellung Zugriff darauf haben sollte.
Synchronisierte Anweisung
Im Gegensatz zu synchronisierten Methoden müssen synchronisierte Anweisungen das Objekt angeben, das die intrinsische Sperre bereitstellt: Meistens verwende ich dies, um den Zugriff auf eine Liste oder Zuordnung zu synchronisieren, möchte jedoch nicht den Zugriff auf alle Methoden des Objekts blockieren.
F: Eigensperren und Synchronisation Die Synchronisation basiert auf einer internen Entität, die als Eigensperre oder Monitorsperre bezeichnet wird. (In der API-Spezifikation wird diese Entität häufig einfach als "Monitor" bezeichnet.) Intrinsische Sperren spielen bei beiden Aspekten der Synchronisierung eine Rolle: Erzwingen des exklusiven Zugriffs auf den Status eines Objekts und Herstellen von Vor-Vor-Beziehungen, die für die Sichtbarkeit wesentlich sind.
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 mit ihnen abgeschlossen 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.
Überprüfen Sie verschiedene Ausgänge mit synchronisierter Methode, Block und ohne Synchronisation.
quelle
Hinweis: Statisch synchronisierte Methoden und Blöcke funktionieren für das Class-Objekt.
quelle
Wenn der Java-Compiler Ihren Quellcode in Bytecode konvertiert, werden synchronisierte Methoden und synchronisierte Blöcke sehr unterschiedlich behandelt.
Wenn die JVM eine synchronisierte Methode ausführt, gibt der ausführende Thread an, dass für die Struktur method_info der Methode das Flag ACC_SYNCHRONIZED gesetzt ist. Anschließend wird die Sperre des Objekts automatisch abgerufen, die Methode aufgerufen und die Sperre aufgehoben. Wenn eine Ausnahme auftritt, gibt der Thread die Sperre automatisch frei.
Das Synchronisieren eines Methodenblocks umgeht andererseits die integrierte Unterstützung der JVM für die Erfassung der Sperr- und Ausnahmebehandlung eines Objekts und erfordert, dass die Funktionalität explizit in Bytecode geschrieben wird. Wenn Sie den Bytecode für eine Methode mit einem synchronisierten Block lesen, werden mehr als ein Dutzend zusätzliche Vorgänge zum Verwalten dieser Funktionalität angezeigt.
Dies zeigt Aufrufe zum Generieren einer synchronisierten Methode und eines synchronisierten Blocks:
Die
synchronizedMethodGet()
Methode generiert den folgenden Bytecode:Und hier ist der Bytecode der
synchronizedBlockGet()
Methode:Ein wesentlicher Unterschied zwischen der synchronisierten Methode und dem Block besteht darin, dass der synchronisierte Block im Allgemeinen den Umfang der Sperre verringert. Da der Umfang der Sperre umgekehrt proportional zur Leistung ist, ist es immer besser, nur kritische Codeabschnitte zu sperren. Eines der besten Beispiele für die Verwendung eines synchronisierten Blocks ist das doppelt überprüfte Sperren im Singleton-Muster, bei dem nicht das Ganze gesperrt wird
getInstance()
Methode nur kritische Codeabschnitte gesperrt werden, die zum Erstellen der Singleton-Instanz verwendet werden. Dies verbessert die Leistung drastisch, da nur ein oder zwei Mal gesperrt werden muss.Bei der Verwendung synchronisierter Methoden müssen Sie besonders vorsichtig sein, wenn Sie sowohl statisch synchronisierte als auch nicht statisch synchronisierte Methoden mischen.
quelle
monitorenter
undmonitorexit
bevor der Code ausgeführt wird .Meistens verwende ich dies, um den Zugriff auf eine Liste oder Karte zu synchronisieren, aber ich möchte den Zugriff auf alle Methoden des Objekts nicht blockieren.
Im folgenden Code blockiert ein Thread, der die Liste ändert, nicht das Warten auf einen Thread, der die Map ändert. Wenn die Methoden für das Objekt synchronisiert würden, müsste jede Methode warten, obwohl die von ihnen vorgenommenen Änderungen nicht in Konflikt stehen würden.
quelle
Mit synchronisierten Blöcken können Sie mehrere Synchronisierer haben, so dass mehrere gleichzeitige, aber nicht widersprüchliche Dinge gleichzeitig ablaufen können.
quelle
Synchronisierte Methoden können mithilfe der Reflection-API überprüft werden. Dies kann zum Testen einiger Verträge hilfreich sein, z. B. wenn alle Methoden im Modell synchronisiert sind .
Das folgende Snippet druckt alle synchronisierten Methoden von Hashtable:
quelle
Wichtiger Hinweis zur Verwendung des synchronisierten Blocks: Achten Sie darauf, was Sie als Sperrobjekt verwenden!
Das Code-Snippet von user2277816 oben veranschaulicht diesen Punkt dahingehend, dass ein Verweis auf ein Zeichenfolgenliteral als Sperrobjekt verwendet wird. Wenn Sie erkennen, dass Zeichenfolgenliterale automatisch in Java interniert werden, sollten Sie das Problem erkennen: Jeder Code, der mit der wörtlichen "Sperre" synchronisiert wird, hat dieselbe Sperre! Dies kann leicht zu Deadlocks mit völlig unabhängigen Codeteilen führen.
Es sind nicht nur String-Objekte, mit denen Sie vorsichtig sein müssen. Boxed Primitive sind ebenfalls eine Gefahr, da Autoboxing und die valueOf-Methoden je nach Wert dieselben Objekte wiederverwenden können.
Weitere Informationen finden Sie unter: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused
quelle
Oft ist die Verwendung einer Sperre auf Methodenebene zu unhöflich. Warum einen Code sperren, der nicht auf gemeinsam genutzte Ressourcen zugreift, indem eine gesamte Methode gesperrt wird? Da jedes Objekt über eine Sperre verfügt, können Sie Dummy-Objekte erstellen, um die Synchronisierung auf Blockebene zu implementieren. Die Blockebene ist effizienter, da nicht die gesamte Methode gesperrt wird.
Hier ein Beispiel
Methodenebene
Block Level
[Bearbeiten]
Für
Collection
likeVector
undHashtable
sie werden synchronisiert, wennArrayList
oderHashMap
nicht und Sie müssen das Schlüsselwort synchronized setzen oder die synchronisierte Methode Collections aufrufen:quelle
Der einzige Unterschied: Synchronisierte Blöcke ermöglichen im Gegensatz zur synchronisierten Methode ein granulares Sperren
Grundsätzlich wurden
synchronized
Blöcke oder Methoden verwendet, um thread-sicheren Code zu schreiben, indem Speicherinkonsistenzfehler vermieden wurden.Diese Frage ist sehr alt und viele Dinge haben sich in den letzten 7 Jahren geändert. Für die Thread-Sicherheit wurden neue Programmierkonstrukte eingeführt.
Sie können Thread-Sicherheit erreichen, indem Sie anstelle von
synchronied
Blöcken die erweiterte Parallelitäts-API verwenden . Diese Dokumentation Seite bietet eine gute Programmierkonstrukte Thread - Sicherheit zu erreichen.Sperrobjekte unterstützen Sperrsprachen, die viele gleichzeitige Anwendungen vereinfachen.
Ausführende definieren eine allgemeine API zum Starten und Verwalten von Threads. Von java.util.concurrent bereitgestellte Executor-Implementierungen bieten eine Thread-Pool-Verwaltung, die für umfangreiche Anwendungen geeignet ist.
Gleichzeitige Sammlungen erleichtern die Verwaltung großer Datensammlungen und können den Synchronisierungsbedarf erheblich reduzieren.
Atomic Variables verfügen über Funktionen, die die Synchronisation minimieren und Speicherkonsistenzfehler vermeiden.
ThreadLocalRandom (in JDK 7) bietet eine effiziente Generierung von Pseudozufallszahlen aus mehreren Threads.
Besserer Ersatz für synchronisierte ist ReentrantLock , das
Lock
API verwendetBeispiel mit Schlössern:
Weitere Programmierkonstrukte finden Sie auch in den Paketen java.util.concurrent und java.util.concurrent.atomic .
Siehe auch diese verwandte Frage:
Synchronisation gegen Sperre
quelle
Die synchronisierte Methode wird zum Sperren aller Objekte verwendet. Der synchronisierte Block wird zum Sperren eines bestimmten Objekts verwendet
quelle
Im Allgemeinen sind diese meistens dieselben, außer dass sie explizit den verwendeten Objektmonitor gegenüber dem impliziten Objekt beschreiben. Ein Nachteil von synchronisierten Methoden, von denen ich denke, dass sie manchmal übersehen werden, ist, dass Sie bei Verwendung der Referenz "this" zum Synchronisieren die Möglichkeit offen lassen, dass externe Objekte dasselbe Objekt sperren. Das kann ein sehr subtiler Fehler sein, wenn Sie darauf stoßen. Durch die Synchronisierung auf einem internen expliziten Objekt oder einem anderen vorhandenen Feld kann dieses Problem vermieden und die Synchronisierung vollständig gekapselt werden.
quelle
Wie hier bereits gesagt, kann der synchronisierte Block eine benutzerdefinierte Variable als Sperrobjekt verwenden, wenn die synchronisierte Funktion nur "dies" verwendet. Und natürlich können Sie mit Bereichen Ihrer Funktion manipulieren, die synchronisiert werden sollen. Aber jeder sagt, dass kein Unterschied zwischen synchronisierter Funktion und Block, der die gesamte Funktion abdeckt, "dies" als Sperrobjekt verwendet. Das ist nicht wahr, der Unterschied liegt im Bytecode, der in beiden Situationen generiert wird. Im Falle einer synchronisierten Blocknutzung sollte eine lokale Variable zugewiesen werden, die auf "this" verweist. Infolgedessen haben wir eine etwas größere Funktion (nicht relevant, wenn Sie nur wenige Funktionen haben).
Eine ausführlichere Erklärung des Unterschieds finden Sie hier: http://www.artima.com/insidejvm/ed2/threadsynchP.html
quelle
Bei synchronisierten Methoden wird die Sperre für ein Objekt erworben. Wenn Sie sich jedoch für einen synchronisierten Block entscheiden, können Sie ein Objekt angeben, für das die Sperre erworben werden soll.
Beispiel:
quelle
Ich weiß, dass dies eine alte Frage ist, aber als ich die Antworten hier schnell gelesen habe, habe ich nicht wirklich gesehen, dass jemand erwähnt hat, dass eine
synchronized
Methode manchmal das falsche Schloss sein kann.Aus der Java-Parallelität in der Praxis (S. 72):
Der obige Code hat das Aussehen von threadsicher sein. In Wirklichkeit ist dies jedoch nicht der Fall. In diesem Fall wird die Sperre für die Instanz der Klasse erhalten. Es ist jedoch möglich, dass die Liste von einem anderen Thread geändert wird, der diese Methode nicht verwendet. Der richtige Ansatz wäre zu verwenden
Der obige Code würde blockieren alle Threads versuchen , zu modifizieren Liste aus Modifizieren der Liste , bis der synchronisierten Block abgeschlossen hat.
quelle
List
kann jedoch zu Leistungsproblemen führen, wenn einIn der Praxis besteht der Vorteil synchronisierter Methoden gegenüber synchronisierten Blöcken darin, dass sie idiotenresistenter sind. Da Sie kein beliebiges Objekt zum Sperren auswählen können, können Sie die synchronisierte Methodensyntax nicht missbrauchen, um dumme Dinge wie das Sperren eines Zeichenfolgenliteral oder das Sperren des Inhalts eines veränderlichen Felds zu tun, das unter den Threads geändert wird.
Andererseits können Sie mit synchronisierten Methoden die Sperre nicht davor schützen, von einem Thread erfasst zu werden, der einen Verweis auf das Objekt erhalten kann.
Die Verwendung von synchronisiert als Modifikator für Methoden schützt Ihre Cow-Orker besser vor Verletzungen, während die Verwendung synchronisierter Blöcke in Verbindung mit privaten Objekten für die endgültige Sperre Ihren eigenen Code besser vor den Cow-Orkern schützt.
quelle
Aus einer Zusammenfassung der Java-Spezifikationen: http://www.cs.cornell.edu/andru/javaspec/17.doc.html
Basierend auf diesen Beschreibungen würde ich sagen, dass die meisten vorherigen Antworten korrekt sind, und eine synchronisierte Methode könnte besonders nützlich sein für statische Methoden, bei denen Sie ansonsten herausfinden müssten, wie Sie das "Klassenobjekt" erhalten, das die Klasse darstellt, in der sich die Methode befand definiert. "
Bearbeiten: Ich dachte ursprünglich, dies wären Zitate der tatsächlichen Java-Spezifikation. Es wurde klargestellt, dass diese Seite nur eine Zusammenfassung / Erklärung der Spezifikation ist
quelle
TLDR; Verwenden Sie weder den
synchronized
Modifikator noch densynchronized(this){...}
Ausdruck, sondernsynchronized(myLock){...}
womyLock
sich ein Endinstanzfeld befindet, das ein privates Objekt enthält.Der Unterschied zwischen der Verwendung des
synchronized
Modifikators für die Methodendeklaration und demsynchronized(..){ }
Ausdruck im Methodenkörper ist folgender:synchronized
in der Signatur der Methode angegebene Modifikatorsynchronized(this) { .... }
undthis
Objekt als Sperre, wenn es für eine nicht statische Methode deklariert wird, oder die einschließende Klasse, wenn es für eine statische Methode deklariert wird.synchronized(...){...}
Ausdruck erlaubt es IhnenDie Verwendung des
synchronized
Modifikators odersynchronized(...) {...}
mitthis
als Sperrobjekt (wie insynchronized(this) {...}
) hat jedoch den gleichen Nachteil. Beide verwenden eine eigene Instanz als Sperrobjekt für die Synchronisierung. Dies ist gefährlich, da nicht nur das Objekt selbst, sondern auch jedes andere externe Objekt / Code, das einen Verweis auf dieses Objekt enthält, es als Synchronisationssperre mit potenziell schwerwiegenden Nebenwirkungen (Leistungseinbußen und Deadlocks ) verwenden kann.Daher wird
synchronized
empfohlen , weder den Modifikator noch densynchronized(...)
Ausdruck in Verbindung mitthis
als Sperrobjekt zu verwenden, sondern ein für dieses Objekt privates Sperrobjekt. Zum Beispiel:Sie können auch mehrere Sperrobjekte verwenden. Es muss jedoch besonders darauf geachtet werden, dass dies bei verschachtelter Verwendung nicht zu Deadlocks führt.
quelle
Ich nehme an, diese Frage betrifft den Unterschied zwischen Thread Safe Singleton und Lazy-Initialisierung mit Double Check Locking . Ich verweise immer auf diesen Artikel, wenn ich einen bestimmten Singleton implementieren muss.
Nun, dies ist ein Thread Safe Singleton :
Dies ist eine Lazy-Initialisierung mit Double Check Locking :
Weitere Informationen finden Sie in diesem Artikel:
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
quelle
Synchronisieren mit Threads. 1) Verwenden Sie NIEMALS synchronisiert (dies) in einem Thread, der nicht funktioniert. Bei der Synchronisierung mit (this) wird der aktuelle Thread als Sperr-Thread-Objekt verwendet. Da jeder Thread unabhängig von anderen Threads ist, erfolgt KEINE Koordination der Synchronisation. 2) Code-Tests zeigen, dass in Java 1.6 auf einem Mac die Methodensynchronisation nicht funktioniert. 3) synchronisiert (lockObj), wobei lockObj ein gemeinsames Objekt aller darauf synchronisierenden Threads ist. 4) ReenterantLock.lock () und .unlock () funktionieren. Siehe dazu Java-Tutorials.
Der folgende Code zeigt diese Punkte. Es enthält auch den thread-sicheren Vektor, der die ArrayList ersetzen würde, um zu zeigen, dass viele Threads, die einem Vektor hinzugefügt werden, keine Informationen verlieren, während dieselben mit einer ArrayList Informationen verlieren können. 0) Der aktuelle Code zeigt einen Informationsverlust aufgrund der Rennbedingungen an. A) Kommentieren Sie die aktuell mit A bezeichnete Linie und kommentieren Sie die darüber liegende A-Linie aus. Führen Sie dann die Methode aus. Die Methode verliert Daten, sollte dies jedoch nicht tun. B) Schritt A umkehren, B auskommentieren und // Block beenden}. Führen Sie dann aus, um die Ergebnisse ohne Datenverlust anzuzeigen. C) Kommentieren Sie B aus, kommentieren Sie C aus. Führen Sie aus, siehe Synchronisieren bei (dies) verliert Daten wie erwartet. Sie haben keine Zeit, alle Variationen zu vervollständigen, hoffen, dass dies hilft. Wenn die Synchronisierung auf (dies) erfolgt oder die Methodensynchronisierung funktioniert, geben Sie bitte an, welche Version von Java und Betriebssystem Sie getestet haben. Vielen Dank.
quelle