wake-up-neo.com

Was ist der Unterschied zwischen einer synchronisierten Methode und einem synchronisierten Block in Java?

Was ist der Unterschied zwischen einer synchronisierten Methode und einem synchronisierten Block in Java?

Ich habe die Antwort im Netz gesucht, die Leute scheinen sich dieser Sache nicht so sicher zu sein :-(

Mein Take wäre, es gibt keinen Unterschied zwischen den beiden, außer dass der Synch-Block im Umfang lokalisierter sein könnte und daher die Sperre von geringerer Zeit sein wird.

Und für den Fall einer statischen Methode, worauf wird die Sperre genommen? Was bedeutet eine Sperrung der Klasse?

35
Geek

Eine synchronisierte Methode verwendet den Methodenempfänger als eine Sperre (d. H. this für nicht statische Methoden und die umgebende Klasse für statische Methoden). Synchronized blocks verwendet den Ausdruck als Sperre.

Die folgenden zwei Methoden sind also gleichbedeutend mit dem Sperren von prospektiven:

synchronized void mymethod() { ... }

void mymethod() {
  synchronized (this) { ... }
}

Bei statischen Methoden wird die Klasse gesperrt:

class MyClass {
  synchronized static mystatic() { ... }

  static mystaticeq() {
    syncrhonized (MyClass.class) { ... }
  }
}

Für synchronisierte Blöcke können Sie ein beliebiges Nicht-null-Objekt als Sperre verwenden:

synchronized (mymap) {
  mymap.put(..., ...);
}

Bereich sperren

Bei synchronisierten Methoden wird die Sperre im gesamten Methodenbereich beibehalten, während im Block synchronized die Sperre nur während dieses Blockbereichs (sonst als kritischer Abschnitt bezeichnet) gehalten wird. In der Praxis kann die JVM durch das Entfernen einiger Operationen aus der synchronized-Blockausführung optimiert werden, wenn sie nachweisen kann, dass sie sicher ausgeführt werden kann.

45
notnoop

Eine synchronisierte Methode ist eine Abkürzung. Diese:

class Something {
    public synchronized void doSomething() {
        ...
    }

    public static synchronized void doSomethingStatic() {
        ...
    }
}

ist in jeder Hinsicht gleichwertig:

class Something {
    public void doSomething() {
        synchronized(this) {
            ...
        }
    }

    public static void doSomethingStatic() {
        synchronized(Something.class) {
            ...
        }
    }
}

(Wobei Something.class das Klassenobjekt für die Klasse Something ist.)

In der Tat können Sie mit einem synchronisierten Block genauer sein, was die Sperre betrifft, und genauer, wann Sie sie verwenden möchten, aber ansonsten gibt es keinen Unterschied.

8
jqno

Ja, das ist ein Unterschied. Zum anderen können Sie eine Sperre für andere Objekte als this erwerben.

3
Henning

Der Hauptunterschied ist folgender: Wenn Sie eine zu synchronisierende Methode deklarieren, wird der gesamte Rumpf der Methode synchronisiert. Wenn Sie den synchronisierten Block verwenden, können Sie jedoch nur den "kritischen Abschnitt" der Methode im synchronisierten Block umgeben, während der Rest der Methode außerhalb des Blocks bleibt.

Wenn die gesamte Methode Teil des kritischen Abschnitts ist, besteht praktisch kein Unterschied. Wenn dies nicht der Fall ist, sollten Sie einen synchronisierten Block nur um den kritischen Abschnitt verwenden. Je mehr Anweisungen Sie in einem synchronisierten Block haben, desto weniger Parallelität erhalten Sie, sodass Sie diese auf ein Minimum beschränken möchten.

Mein Take wäre, es gibt keinen Unterschied zwischen den beiden, außer dass der Synch-Block im Geltungsbereich lokaler sein könnte und daher die Sperre weniger Zeit hat?

Ja. Du hast recht. Im Gegensatz zu synchronized-Methoden müssen synchronisierte Anweisungen das Objekt angeben, das die intrinsische Sperre bereitstellt.

Beispiel aus einem Java-Tutorial:

public void addName(String name) {
    synchronized(this) {
        lastName = name;
        nameCount++;
    }
    nameList.add(name);
}

Synchronisierte Anweisungen sind auch nützlich, um die Parallelität mit fein abgestimmter Synchronisation zu verbessern. Ein gutes Beispiel finden Sie auf derselben Tutorial-Seite für den folgenden Anwendungsfall.

Angenommen, die Klasse MsLunch hat zwei Instanzfelder, c1 und c2, die niemals zusammen verwendet werden. Alle Aktualisierungen dieser Felder müssen synchronized sein. Es gibt jedoch keinen Grund, zu verhindern, dass ein Update von c1 mit einem Update von c2 verschachtelt wird. Dadurch wird die Parallelität durch das Erstellen unnötiger Blockierungen reduziert. Anstatt synchronisierte Methoden zu verwenden oder die damit verknüpfte Sperre anderweitig zu verwenden, erstellen wir zwei Objekte, die ausschließlich Sperren bereitstellen.

Und für den Fall einer statischen Methode, worauf wird die Sperre genommen? Was bedeutet eine Sperrung der Klasse?

In diesem Fall erhält der Thread die intrinsische Sperre für das der Klasse zugeordnete Klassenobjekt. Daher wird der Zugriff auf die statischen Felder der Klasse durch eine Sperre gesteuert, die sich von der Sperre für jede Instanz der Klasse unterscheidet.

Wenn Sie eine Methode als synchronized (nicht static) erstellen:

Es ist nicht möglich, zwei Aufrufe von synchronized-Methoden für dasselbe Objekt zu verschachteln. Wenn ein Thread eine synchronisierte Methode für ein Objekt ausführt, werden alle anderen Threads, die synchronisierte Methoden für denselben Objektblock aufrufen (Suspend-Ausführung), bis der erste Thread mit dem Objekt fertig ist.

Wenn Sie eine Methode als static synchronized erstellen:

Es ist nicht möglich, dass zwei Aufrufe von static synchronized-Methoden für verschiedene Objekte derselben Klasse verschachtelt werden. Wenn ein Thread eine static synchronized-Methode für ein Objekt der Klasse A ausführt, werden alle anderen Threads, die static synchronized-Methoden für Objekte der Klasse A (Suspend-Ausführung) aufrufen, bis der erste Thread mit der Methodenausführung fertig ist.

In dieser SE-Frage finden Sie bessere Alternativen zur Synchronisierung:

Vermeiden Sie (dies) in Java synchronisiert?

0
Ravindra babu

Eine synchronisierte Methode sperrt die Objektinstanz, in der die Methode enthalten ist.

Wo ein synchronisierter Block ein beliebiges Objekt sperren kann - normalerweise ein Mutex-Objekt, das als Instanzvariable definiert ist. Dies ermöglicht eine bessere Kontrolle darüber, welche Sperren in Betrieb sind.

0
madlep