Ich habe angefangen, Synchronisation im Threading zu lernen.
Synchronisierte Methode:
public class Counter {
private static int count = 0;
public static synchronized int getCount() {
return count;
}
public synchronized setCount(int count) {
this.count = count;
}
}
Synchronisierter Block:
public class Singleton {
private static volatile Singleton _instance;
public static Singleton getInstance() {
if (_instance == null) {
synchronized(Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
Wann sollte ich synchronized
Methode und synchronized
Block verwenden?
Warum ist synchronized
Block besser als synchronized
Methode?
java
multithreading
synchronization
Sabapathie
quelle
quelle
enum
für einen Singleton verwenden.Antworten:
Es geht nicht besser, nur anders.
Wenn Sie eine Methode synchronisieren, synchronisieren Sie effektiv mit dem Objekt selbst. Bei einer statischen Methode synchronisieren Sie mit der Klasse des Objekts. Die folgenden zwei Codeteile werden also auf dieselbe Weise ausgeführt:
public synchronized int getCount() { // ... }
Das ist genau so, wie du das geschrieben hast.
public int getCount() { synchronized (this) { // ... } }
Wenn Sie die Synchronisation mit einem bestimmten Objekt steuern möchten oder nur ein Teil einer Methode mit dem Objekt synchronisiert werden soll, geben Sie einen
synchronized
Block an. Wenn Sie dassynchronized
Schlüsselwort in der Methodendeklaration verwenden, wird die gesamte Methode mit dem Objekt oder der Klasse synchronisiert.quelle
this
sodass diese Antwort den Punkt ein wenig verfehlt.this
. In der Tat ist es ein Vorteil, wenn Sie eine Reihe synchronisierter Methoden nacheinander aufrufen möchten. Sie können das Objekt für die Dauer synchronisieren und müssen sich nicht um das Freigeben und erneute Abrufen von Sperren für jeden Methodenaufruf kümmern. Es gibt viele verschiedene Muster, die für die Synchronisation verwendet werden können, und jedes hat je nach Situation seine eigenen Vor- und Nachteile.synchronized(someObj)
. Tatsächlich generiert der Compiler Code für die Synchronisierung, als obsomeObj==this
. Dies hat also keinen Vorteil, aber Sie setzen interne Details der Außenwelt aus, wodurch die Kapselung eindeutig unterbrochen wird. Nun, es gibt einen Vorteil: Sie sparen ungefähr 20 Byte.Obwohl dies aus Sicherheitsgründen normalerweise kein Problem darstellt, ist es besser, die Synchronisierung für ein privates Objekt zu verwenden, als es für eine Methode zu verwenden.
Wenn Sie es auf die Methode setzen, verwenden Sie die Sperre des Objekts selbst, um die Thread-Sicherheit zu gewährleisten. Mit dieser Art von Mechanismus kann ein böswilliger Benutzer Ihres Codes auch die Sperre für Ihr Objekt erhalten und für immer behalten, wodurch andere Threads effektiv blockiert werden. Ein nicht böswilliger Benutzer kann das gleiche versehentlich tun.
Wenn Sie die Sperre eines privaten Datenelements verwenden, können Sie dies verhindern, da ein böswilliger Benutzer die Sperre für Ihr privates Objekt nicht erhalten kann.
private final Object lockObject = new Object(); public void getCount() { synchronized( lockObject ) { ... } }
Diese Technik wird in Blochs Effective Java (2. Aufl.), Punkt 70 erwähnt
quelle
synchronized
Block als das "Ihr privates Objekt" verwendet?Der Unterschied besteht darin, in welcher Sperre erworben wird:
Die synchronisierte Methode erhält eine Sperre für das gesamte Objekt. Dies bedeutet, dass kein anderer Thread eine synchronisierte Methode im gesamten Objekt verwenden kann, während die Methode von einem Thread ausgeführt wird.
synchronisierte Blöcke erhalten nach dem synchronisierten Schlüsselwort eine Sperre im Objekt zwischen Klammern. Dies bedeutet, dass kein anderer Thread eine Sperre für das gesperrte Objekt erhalten kann, bis der synchronisierte Block beendet wird.
Wenn Sie also das gesamte Objekt sperren möchten, verwenden Sie eine synchronisierte Methode. Wenn Sie andere Teile des Objekts für andere Threads zugänglich machen möchten, verwenden Sie den synchronisierten Block.
Wenn Sie das gesperrte Objekt sorgfältig auswählen, führen synchronisierte Blöcke zu weniger Konflikten, da das gesamte Objekt / die gesamte Klasse nicht blockiert wird.
Dies gilt ähnlich für statische Methoden: Eine synchronisierte statische Methode erhält eine Sperre für das gesamte Klassenobjekt, während ein synchronisierter Block innerhalb einer statischen Methode eine Sperre für das Objekt zwischen Klammern erhält.
quelle
Definieren Sie "besser". Ein synchronisierter Block ist nur deshalb besser, weil Sie Folgendes können:
Ihr spezielles Beispiel ist nun ein Beispiel für das doppelt überprüfte Sperrmuster , das verdächtig ist (in älteren Java-Versionen war es fehlerhaft und es ist leicht, es falsch zu machen).
Wenn Ihre Initialisierung billig ist, ist es möglicherweise besser, sofort mit einem letzten Feld zu initialisieren, und nicht bei der ersten Anforderung würde auch die Notwendigkeit einer Synchronisierung beseitigt.
quelle
Der Unterschied zwischen dem synchronisierten Block und der synchronisierten Methode ist folgender:
synchronisierter Block:
synchronized(this){}
synchronisierte Methode:
public synchronized void fun(){}
quelle
synchronisiert sollte nur verwendet werden, wenn Ihre Klasse threadsicher sein soll. Tatsächlich sollten die meisten Klassen sowieso nicht synchronisiert verwenden. Die synchronisierte Methode würde nur eine Sperre für dieses Objekt und nur für die Dauer seiner Ausführung bereitstellen . Wenn Sie Ihre Klassen wirklich threadsicher machen möchten , sollten Sie in Betracht ziehen, Ihre Variablen flüchtig zu machen oder den Zugriff zu synchronisieren .
Eines der Probleme bei der Verwendung der synchronisierten Methode besteht darin, dass alle Mitglieder der Klasse dieselbe Sperre verwenden, wodurch Ihr Programm langsamer wird. In Ihrem Fall würden synchronisierte Methode und Block nicht anders ausgeführt. Ich würde empfehlen, ein dediziertes Schloss und einen synchronisierten Block wie diesen zu verwenden.
public class AClass { private int x; private final Object lock = new Object(); //it must be final! public void setX() { synchronized(lock) { x++; } } }
quelle
In Ihrem Fall sind beide gleichwertig!
Das Synchronisieren einer statischen Methode entspricht einem synchronisierten Block für das entsprechende Klassenobjekt.
Wenn Sie eine synchronisierte statische Methodensperre deklarieren, wird auf dem Monitor, der dem Class-Objekt entspricht, eine Sperre erhalten.
public static synchronized int getCount() { // ... }
ist das gleiche wie
public int getCount() { synchronized (ClassName.class) { // ... } }
quelle
Da das Sperren teuer ist, sperren Sie bei Verwendung eines synchronisierten Blocks nur dann, wenn Sie
_instance == null
nach der_instance
endgültigen Initialisierung niemals sperren. Wenn Sie jedoch eine Methode synchronisieren, werden Sie auch nach der_instance
Initialisierung bedingungslos gesperrt. Dies ist die Idee hinter dem doppelt überprüften Optimierungsmuster für Sperren http://en.wikipedia.org/wiki/Double-checked_locking .quelle
Es sollte nicht als eine Frage der besten Verwendung angesehen werden, aber es hängt wirklich vom Anwendungsfall oder vom Szenario ab.
Synchronisierte Methoden
Eine gesamte Methode kann als synchronisiert markiert werden, was zu einer impliziten Sperre dieser Referenz (Instanzmethoden) oder Klasse (statische Methoden) führt. Dies ist ein sehr praktischer Mechanismus, um eine Synchronisation zu erreichen.
Schritte Ein Thread greift auf die synchronisierte Methode zu. Es erwirbt implizit die Sperre und führt den Code aus. Wenn ein anderer Thread auf die obige Methode zugreifen möchte, muss er warten. Der Thread kann die Sperre nicht erhalten, wird blockiert und muss warten, bis die Sperre aufgehoben wird.
Synchronisierte Blöcke
Um eine Sperre für ein Objekt für einen bestimmten Satz von Codeblöcken zu erhalten, sind synchronisierte Blöcke am besten geeignet. Da ein Block ausreicht, ist die Verwendung einer synchronisierten Methode eine Verschwendung.
Insbesondere mit Synchronized Block ist es möglich, die Objektreferenz zu definieren, für die eine Sperre erworben werden soll.
quelle
Ein klassischer Unterschied zwischen dem synchronisierten Block und der synchronisierten Methode besteht darin, dass die synchronisierte Methode das gesamte Objekt sperrt. Der synchronisierte Block sperrt nur den Code innerhalb des Blocks.
Synchronisierte Methode: Grundsätzlich deaktivieren diese beiden Synchronisierungsmethoden das Multithreading. Ein Thread vervollständigt also die Methode1 () und der andere Thread wartet auf die Fertigstellung von Thread1.
Klasse SyncExerciseWithSyncMethod {
public synchronized void method1() { try { System.out.println("In Method 1"); Thread.sleep(5000); } catch (Exception e) { System.out.println("Catch of method 1"); } finally { System.out.println("Finally of method 1"); } } public synchronized void method2() { try { for (int i = 1; i < 10; i++) { System.out.println("Method 2 " + i); Thread.sleep(1000); } } catch (Exception e) { System.out.println("Catch of method 2"); } finally { System.out.println("Finally of method 2"); } }
}}
Ausgabe
In Methode 1
Schließlich von Methode 1
Methode 2 1
Methode 2 2
Methode 2 3
Methode 2 4
Methode 2 5
Methode 2 6
Methode 2 7
Methode 2 8
Methode 2 9
Schließlich von Methode 2
Synchronisierter Block: Ermöglicht mehreren Threads den gleichzeitigen Zugriff auf dasselbe Objekt [Aktiviert Multithreading].
Klasse SyncExerciseWithSyncBlock {
public Object lock1 = new Object(); public Object lock2 = new Object(); public void method1() { synchronized (lock1) { try { System.out.println("In Method 1"); Thread.sleep(5000); } catch (Exception e) { System.out.println("Catch of method 1"); } finally { System.out.println("Finally of method 1"); } } } public void method2() { synchronized (lock2) { try { for (int i = 1; i < 10; i++) { System.out.println("Method 2 " + i); Thread.sleep(1000); } } catch (Exception e) { System.out.println("Catch of method 2"); } finally { System.out.println("Finally of method 2"); } } }
}}
Ausgabe
In Methode 1
Methode 2 1
Methode 2 2
Methode 2 3
Methode 2 4
Methode 2 5
Schließlich von Methode 1
Methode 2 6
Methode 2 7
Methode 2 8
Methode 2 9
Schließlich von Methode 2
quelle