Java-synchronisierte statische Methoden: Objekt oder Klasse sperren


147

In der Java-Dokumentation heißt es:

Es ist nicht möglich, dass zwei Aufrufe synchronisierter Methoden für dasselbe Objekt verschachtelt werden.

Was bedeutet das für eine statische Methode? Da eine statische Methode keinem Objekt zugeordnet ist, wird das synchronisierte Schlüsselwort die Klasse anstelle des Objekts sperren?

Antworten:


128

Da einer statischen Methode kein Objekt zugeordnet ist, wird das synchronisierte Schlüsselwort die Klasse anstelle des Objekts sperren?

Ja. :) :)


81
Bitte antworten Sie auf Ausarbeiten, damit jeder verstehen kann.
Madhu

6
@ Madhu. Wenn Sie zwei oder mehr synchronisierte Methoden in derselben Klasse haben, können beide nicht gleichzeitig ausgeführt werden, selbst wenn mehrere Instanzen dieser Klasse vorhanden sind. Das Sperren entspricht im Wesentlichen dem Sperren der Object.class für jede synchronisierte Methode.
Steven

Diese Antwort ist falsch - thisist die Sperre für Instanzmethoden erworben -, bitte beheben Sie sie Oscar.
vemv

1
@vemv Die Frage bezieht sich auf Klassenmethoden, nicht auf Instanzmethoden.
OscarRyz

23
@vemv Nun ja, um die Antwort zu verstehen, müssen Sie zuerst die Frage lesen.
OscarRyz

199

Um der Antwort von Oscar (erfreulich prägnant!) Ein kleines Detail hinzuzufügen, lautet der relevante Abschnitt in der Java-Sprachspezifikation 8.4.3.6, 'Synchronisierte Methoden' :

Eine synchronisierte Methode erfasst einen Monitor ( §17.1 ), bevor er ausgeführt wird. Für eine Klassenmethode (statisch) wird der Monitor verwendet, der dem Class-Objekt für die Klasse der Methode zugeordnet ist. Für eine Instanzmethode wird der dazugehörige Monitor (das Objekt, für das die Methode aufgerufen wurde) verwendet.


17
Nützlich, ich suchte nach diesem Zitat +1
OscarRyz

80

Ein Punkt, bei dem Sie vorsichtig sein müssen (mehrere Programmierer fallen im Allgemeinen in diese Falle), ist, dass es keine Verbindung zwischen synchronisierten statischen Methoden und synchronisierten nicht statischen Methoden gibt, dh:

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

Main:

A a = new A();

Thread 1:

A.f();

Thread 2:

a.g();

f () und g () sind nicht miteinander synchronisiert und können daher vollständig gleichzeitig ausgeführt werden.


18
aber was ist, wenn g () eine statische Variable mutiert, die f () liest? Wie machen wir diesen Thread sicher? Erhalten wir dann explizit eine Sperre für die Klasse?
Baskin

22
Ja, Ihre nicht-statische Methode muss auf der Klasse explizit synchronisieren selbst (dh synchronized (MyClass.class) {...}.
jfpoilpret

@jfpoilpret "synchronized (MyClass.class) {...}" entspricht der statischen Synchronisierung dieser Methode, oder?
Crazymind

15

Es sei denn, Sie implementieren g () wie folgt:

g() {
    synchronized(getClass()) {
        ...
    }
}

Ich finde dieses Muster auch nützlich, wenn ich den gegenseitigen Ausschluss zwischen verschiedenen Instanzen des Objekts implementieren möchte (was beispielsweise beim Zugriff auf eine externe Ressource erforderlich ist).


63
Beachten Sie, dass hier möglicherweise sehr subtile und böse Fehler auftreten können. Denken Sie daran, dass getClass()der Laufzeittyp zurückgegeben wird . Wenn Sie die Klasse unterordnen, werden die übergeordnete Klasse und die untergeordnete Klasse auf verschiedenen Sperren synchronisiert. synchronized(MyClass.class)Dies ist der richtige Weg, wenn Sie sicherstellen möchten, dass alle Instanzen dieselbe Sperre verwenden.
Cowan

4

Schauen Sie sich die Oracle-Dokumentationsseite zu Intrinsic Locks and Synchronization an

Sie fragen sich möglicherweise, was passiert, wenn eine statisch synchronisierte Methode aufgerufen wird, da eine statische Methode einer Klasse und nicht einem Objekt zugeordnet ist. In diesem Fall erhält der Thread die intrinsische Sperre für das der Klasse zugeordnete Class-Objekt . Somit 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 .


2

Einer statischen Methode ist auch ein Objekt zugeordnet. Es gehört zur Class.class-Datei im JDK-Toolkit. Wenn die .class-Datei in den RAM geladen wird, erstellt die Class.class eine Instanz davon, die als Vorlagenobjekt bezeichnet wird.

Beispiel: - Wenn Sie versuchen, ein Objekt aus einer vorhandenen Kundenklasse wie zu erstellen

Customer c = new Customer();

Die Customer.class wird in den RAM geladen. In diesem Moment erstellt Class.class im JDK-Toolkit ein Objekt namens Template-Objekt und lädt diese Customer.class in dieses Template-Objekt. Statische Mitglieder dieser Customer.class werden zu Attributen und Methoden in diesem Template-Objekt.

Eine statische Methode oder ein statisches Attribut hat also auch ein Objekt


2

Die folgenden Beispiele geben mehr Klarheit zwischen Klassen- und Objektsperre. Ich hoffe, das folgende Beispiel hilft auch anderen :)

Zum Beispiel haben wir folgende Methoden: eine Erfassungsklasse und eine andere Erfassungsobjektsperre:

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

Jetzt können wir also folgende Szenarien haben:

  1. Wenn Threads, die dasselbe Objekt verwenden, gleichzeitig versuchen, auf die objLock OR- staticLock Methode zuzugreifen (dh beide Threads versuchen, auf dieselbe Methode zuzugreifen)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  2. Wenn Threads, die dasselbe Objekt verwenden, gleichzeitig versuchen, auf Methoden staticLockund objLockMethoden zuzugreifen (versucht, auf verschiedene Methoden zuzugreifen)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
  3. Wenn Threads, die ein anderes Objekt verwenden, versuchen, auf die staticLockMethode zuzugreifen

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  4. Wenn Threads, die ein anderes Objekt verwenden, versuchen, auf die objLockMethode zuzugreifen

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4

0

Für diejenigen, die nicht mit der statischen synchronisierten Methode vertraut sind, die für das Klassenobjekt gesperrt ist, z. B. für die Zeichenfolgenklasse, wird die String.class gesperrt, während die instanzsynchronisierte Methode die aktuelle Instanz des Objekts sperrt, die in Java mit dem Schlüsselwort "this" gekennzeichnet ist. Da beide Objekte unterschiedlich sind, haben sie unterschiedliche Sperren. Während ein Thread eine statisch synchronisierte Methode ausführt, muss ein anderer Thread in Java nicht auf die Rückkehr dieses Threads warten, sondern erhält eine separate Sperre, die als Byte .class-Literal bezeichnet wird, und tritt ein statisch synchronisierte Methode.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.