Metodi statici sincronizzati Java: blocco su oggetto o classe


148

La documentazione Java dice:

Non è possibile per due invocazioni di metodi sincronizzati sullo stesso oggetto interleave.

Cosa significa questo per un metodo statico? Poiché un metodo statico non ha oggetti associati, la parola chiave sincronizzata si bloccherà sulla classe anziché sull'oggetto?

Risposte:


129

Poiché un metodo statico non ha oggetti associati, la parola chiave sincronizzata si bloccherà sulla classe anziché sull'oggetto?

Sì. :)


81
Rispondi a Elaborate in modo che tutti possano capire.
Madhu,

6
@Madhu. Significa che se hai 2 o più metodi sincronizzati sulla stessa classe, entrambi non possono essere eseguiti contemporaneamente, anche quando ci sono più istanze di quella classe. Il blocco è essenzialmente uguale al blocco su Object.class per ciascun metodo sincronizzato.
Steven,

Questa risposta è sbagliata - thisè il blocco acquisito sui metodi di istanza -, per favore, aggiustalo Oscar.
Vemv,

1
@vemv La domanda riguarda i metodi di classe, non i metodi di istanza.
OscarRyz,

23
@vemv Beh, sì, per capire la risposta devi prima leggere la domanda.
OscarRyz

199

Solo per aggiungere un piccolo dettaglio alla risposta di Oscar (piacevolmente concisa!), La sezione pertinente sulla specifica del linguaggio Java è 8.4.3.6, "Metodi sincronizzati" :

Un metodo sincronizzato acquisisce un monitor ( §17.1 ) prima che venga eseguito. Per un metodo di classe (statico), viene utilizzato il monitor associato all'oggetto Class per la classe del metodo. Per un metodo di istanza, viene utilizzato il monitor associato a questo (l'oggetto per cui è stato invocato il metodo).


17
Utile, stavo cercando quella citazione +1
OscarRyz

80

Un punto su cui devi stare attento (molti programmatori generalmente cadono in quella trappola) è che non esiste alcun legame tra metodi statici sincronizzati e metodi non statici sincronizzati, ovvero:

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

Principale:

A a = new A();

Discussione 1:

A.f();

Discussione 2:

a.g();

f () e g () non sono sincronizzati tra loro e quindi possono essere eseguiti contemporaneamente.


18
ma cosa succede se g () sta mutando una variabile statica che f () sta leggendo. Come possiamo rendere sicuro quel thread? Allora acquisiamo esplicitamente un lucchetto sulla classe?
baskin

22
Sì, il tuo metodo non statico deve sincronizzarsi esplicitamente sulla classe stessa (ad es synchronized (MyClass.class) {...}.
jfpoilpret,

@jfpoilpret "sincronizzato (MyClass.class) {...}" equivale a rendere questo metodo statico sincronizzato, giusto?
crazymind,

15

A meno che non implementiate g () come segue:

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

Trovo questo schema utile anche quando voglio implementare l'esclusione reciproca tra diverse istanze dell'oggetto (che è necessario quando si accede a una risorsa esterna, per esempio).


63
Nota che qui potrebbe esserci la possibilità di alcuni bug molto sottili e cattivi. Ricorda getClass()restituisce il tipo di runtime ; se si esegue la sottoclasse della classe, la classe genitore e la classe figlio si sincronizzeranno su blocchi diversi. synchronized(MyClass.class)è la strada da percorrere se è necessario assicurarsi che tutte le istanze utilizzino lo stesso blocco.
Cowan,

4

Dai un'occhiata alla pagina della documentazione di Oracle su Intrinsic Locks and Synchronization

Potresti chiederti cosa succede quando viene invocato un metodo sincronizzato statico, poiché un metodo statico è associato a una classe, non a un oggetto. In questo caso, il thread acquisisce il blocco intrinseco per l'oggetto Class associato alla classe . Pertanto, l'accesso ai campi statici della classe è controllato da un blocco distinto dal blocco per qualsiasi istanza della classe .


2

Un metodo statico ha anche un oggetto associato. Appartiene al file Class.class nel toolkit JDK. Quando il file .class viene caricato nella ram, Class.class crea un'istanza di esso denominata oggetto template.

Ad esempio: - quando si tenta di creare oggetti da una classe cliente esistente come

Customer c = new Customer();

La classe Customer.class viene caricata nella RAM. In quel momento Class.class nel toolkit JDK crea un oggetto chiamato oggetto Template e carica quel Customer.class nell'oggetto template. I membri statici di quel Customer.class diventano attributi e metodi nell'oggetto template.

Quindi anche un metodo o un attributo statico ha un oggetto


2

Gli esempi di seguito forniscono maggiore chiarezza tra classe e blocco degli oggetti, la speranza sotto l'esempio aiuterà anche gli altri :)

Ad esempio abbiamo sotto i metodi uno acquisiscono classe e l'altro acquisiscono il blocco dell'oggetto:

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);
        }
    }
}

Quindi, ora possiamo avere i seguenti scenari:

  1. Quando i thread che utilizzano lo stesso oggetto tentano di accedere allo stesso metodo objLock OR staticLock (ovvero entrambi i thread stanno tentando di accedere allo stesso metodo)

    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. Quando i thread che utilizzano lo stesso oggetto tentano di accedere staticLocke objLockmetodi allo stesso tempo (tentano di accedere a metodi diversi)

    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. Quando i thread che utilizzano oggetti diversi tentano di accedere al staticLockmetodo

    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. Quando i thread che utilizzano oggetti diversi tentano di accedere al objLockmetodo

    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

Per coloro che non hanno familiarità con il metodo sincronizzato statico bloccato sull'oggetto classe, ad esempio per la classe stringa, String.class mentre il metodo sincronizzato dell'istanza si blocca sull'istanza corrente dell'oggetto indicato con la parola chiave "this" in Java. Poiché entrambi questi oggetti sono diversi, hanno un blocco diverso, quindi mentre un thread sta eseguendo un metodo sincronizzato statico, l'altro thread in java non ha bisogno di aspettare che quel thread ritorni, ma acquisirà un byte separato indicato da un blocco .class letterale ed entrerà in metodo sincronizzato statico.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.