Kann mir jemand den Vorteil einer synchronisierten Methode gegenüber einem synchronisierten Block anhand eines Beispiels erläutern?
Antworten
Zu viele Anzeigen?Wichtiger Hinweis zur Verwendung des synchronisierten Blocks: Passen Sie auf, was Sie als Lock-Objekt verwenden!
Der obige Codeschnipsel von user2277816 veranschaulicht dies, indem ein Verweis auf ein Stringliteral als Sperrobjekt verwendet wird. Wenn man sich vergegenwärtigt, dass Stringliterale in Java automatisch interniert werden, wird das Problem deutlich: Jeder Code, der sich mit dem Literal "lock" synchronisiert, teilt sich dieselbe Sperre! Dies kann leicht zu Deadlocks mit völlig unverbundenen Teilen des Codes führen.
Es sind nicht nur String-Objekte, mit denen Sie vorsichtig umgehen müssen. Boxed Primitives sind ebenfalls eine Gefahr, da Autoboxing und die valueOf-Methoden dieselben Objekte je nach Wert wiederverwenden können.
Für weitere Informationen siehe: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Nicht+synchronisieren+auf+Objekte+die+wieder+verwendet+werden+können
Oft ist die Verwendung eines Schlosses auf einer Methodenebene zu unhöflich. Warum sollte man einen Teil des Codes sperren, der auf keine gemeinsamen Ressourcen zugreift, indem man eine ganze Methode sperrt? Da jedes Objekt eine Sperre hat, können Sie Dummy-Objekte erstellen, um die Synchronisierung auf Blockebene zu implementieren. Die Blockebene ist effizienter, da sie nicht die gesamte Methode sperrt.
Hier einige Beispiele
Methode Ebene
class MethodLevel {
//shared among threads
SharedResource x, y ;
public void synchronized method1() {
//multiple threads can't access
}
public void synchronized method2() {
//multiple threads can't access
}
public void method3() {
//not synchronized
//multiple threads can access
}
}
Blockebene
class BlockLevel {
//shared among threads
SharedResource x, y ;
//dummy objects for locking
Object xLock = new Object();
Object yLock = new Object();
public void method1() {
synchronized(xLock){
//access x here. thread safe
}
//do something here but don't use SharedResource x, y
// because will not be thread-safe
synchronized(xLock) {
synchronized(yLock) {
//access x,y here. thread safe
}
}
//do something here but don't use SharedResource x, y
//because will not be thread-safe
}//end of method1
}
[Bearbeiten]
Für Collection
wie Vector
y Hashtable
sie synchronisiert werden, wenn ArrayList
o HashMap
sind nicht und Sie müssen das Schlüsselwort synchronized setzen oder die Methode Collections synchronized aufrufen:
Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
Der einzige Unterschied: synchronisierte Blöcke ermöglichen im Gegensatz zu synchronisierten Methoden granulare Sperren
Grundsätzlich synchronized
Block oder Methoden wurden verwendet, um thread-sicheren Code zu schreiben, indem Speicherinkonsistenzfehler vermieden werden.
Diese Frage ist sehr alt und in den letzten 7 Jahren hat sich vieles geändert. Es wurden neue Programmierkonstrukte für die Threadsicherheit eingeführt.
Sie können Thread-Sicherheit erreichen, indem Sie die erweiterte Gleichzeitigkeits-API anstelle von synchronied
Blöcke. Diese Dokumentation Seite bietet gute Programmierkonstrukte, um Threadsicherheit zu erreichen.
Objekte sperren unterstützen Locking Idioms, die viele nebenläufige Anwendungen vereinfachen.
Testamentsvollstrecker definieren eine High-Level-API zum Starten und Verwalten von Threads. Executor-Implementierungen, die von java.util.concurrent bereitgestellt werden, bieten eine Thread-Pool-Verwaltung, die für umfangreiche Anwendungen geeignet ist.
Gleichzeitige Sammlungen erleichtern die Verwaltung großer Datensammlungen und können den Bedarf an Synchronisierung erheblich reduzieren.
Atomare Variablen haben Funktionen, die die Synchronisierung minimieren und helfen, Speicherkonsistenzfehler zu vermeiden.
ThreadLocalRandom (in JDK 7) ermöglicht die effiziente Erzeugung von Pseudozufallszahlen aus mehreren Threads.
Ein besserer Ersatz für synchronisiert ist ReentrantLock , die die Lock
API
Eine reentrante gegenseitige Ausschlusssperre mit demselben grundlegenden Verhalten und derselben Semantik wie die implizite Monitorsperre, auf die mit synchronisierten Methoden und Anweisungen zugegriffen wird, jedoch mit erweiterten Fähigkeiten.
Beispiel mit Schlössern:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
Siehe java.util.concurrent y java.util.concurrent.atomic Pakete auch für andere Programmierkonstrukte.
Siehe auch diese verwandte Frage:
Im Allgemeinen sind diese größtenteils gleich, abgesehen davon, dass der Monitor des Objekts, der verwendet wird, explizit ist, im Gegensatz zu dem impliziten this object. Ein Nachteil von synchronisierten Methoden, der meiner Meinung nach manchmal übersehen wird, ist, dass bei der Verwendung der "this"-Referenz zum Synchronisieren die Möglichkeit besteht, dass externe Objekte dasselbe Objekt sperren. Das kann ein sehr subtiler Fehler sein, wenn Sie darauf stoßen. Die Synchronisierung auf ein internes explizites Objekt oder ein anderes vorhandenes Feld kann dieses Problem vermeiden, indem die Synchronisierung vollständig gekapselt wird.