Blocco sincronizzato Java per .class


Risposte:


144

Lo snippet synchronized(X.class)utilizza l'istanza della classe come monitor. Poiché esiste una sola istanza di classe (l'oggetto che rappresenta i metadati della classe in fase di esecuzione), un thread può essere in questo blocco.

Con synchronized(this)il blocco è custodito dall'istanza. Per ogni istanza solo un thread può entrare nel blocco.

synchronized(X.class)viene utilizzato per assicurarsi che ci sia esattamente un thread nel blocco. synchronized(this)assicura che ci sia esattamente un thread per istanza. Se questo rende il codice effettivo nel blocco thread-safe dipende dall'implementazione. Se muta synchronized(this)è sufficiente solo lo stato dell'istanza .


6
"tanti thread possono entrare nel blocco quante sono le istanze" implica che la seconda forma agisce come un semaforo che non è vero. Dovresti dire qualcosa come: "synchronized (this) assicura che solo un thread possa entrare nel blocco per una data istanza della classe".
liwp

Corretto. Avevo intenzione di dirlo.
Thomas Jung

2
qual è l'istanza della classe rispetto all'istanza?
Weishi Zeng

Quindi, se hai un metodo statico e non vogliamo sincronizzare tutto il suo corpo, allora abbiamo sincronizzato (questo) non va bene, invece sincronizzato (Foo.class) è appropriato. È giusto?
krupal.agile

84

Da aggiungere alle altre risposte:

static void myMethod() {
  synchronized(MyClass.class) {
    //code
  }
}

è equivalente a

static synchronized void myMethod() {
  //code
}

e

void myMethod() {
  synchronized(this) {
    //code
  }
}

è equivalente a

synchronized void myMethod() {
  //code
}

12
Mi ci è voluta una seconda lettura per capire che i primi due esempi hanno la parola chiave "statico". Lo faccio solo notare ad altri che potrebbero averlo visto e non averlo visto. Senza la parola chiave statica i primi due esempi non sarebbero gli stessi.
kurtzbot

1
Questi esempi NON sono equivalenti! I metodi sincronizzati vengono "sincronizzati" come un buco quando un thread tenta di chiamare i metodi. I blocchi d'altra parte, possono avere codice sopra e sotto di loro, che può essere eseguito da più thread. Si sincronizzano solo all'interno del blocco! Non è la stessa cosa!
JacksOnF1re

public static Singleton getInstance () {if (instance == null) {synchronized (Singleton.class) {instance = new Singleton (); }} istanza di ritorno; }
JacksOnF1re

2
Il punto è che non v'è alcun codice di fuori dei synchronizedblocchi. Questo li rende equivalenti. Se cambi un esempio, in effetti non sono più la stessa cosa.
Jorn

23

No, il primo otterrà un blocco sulla definizione della classe MyClass, non su tutte le sue istanze. Tuttavia, se utilizzato in un'istanza, bloccherà efficacemente tutte le altre istanze, poiché condividono una singola definizione di classe.

Il secondo otterrà un blocco solo sull'istanza corrente.

Per quanto riguarda se questo rende i tuoi oggetti thread-safe, questa è una domanda molto più complessa: avremmo bisogno di vedere il tuo codice!


1
sì, MyClass.class potrebbe essere qualsiasi variabile statica e avere lo stesso effetto.
pstanton

0

Sì lo farà (su qualsiasi blocco / funzione sincronizzato).

Mi stavo chiedendo questa domanda per un paio di giorni per me stesso (in realtà in kotlin). Finalmente ho trovato una buona spiegazione e voglio condividerla:

Il blocco a livello di classe impedisce a più thread di entrare nel blocco sincronizzato in una qualsiasi di tutte le istanze disponibili della classe in runtime. Ciò significa che se in runtime sono presenti 100 istanze di DemoClass, allora solo un thread sarà in grado di eseguire demoMethod () in una qualsiasi delle istanze alla volta e tutte le altre istanze saranno bloccate per altri thread.

Il blocco a livello di classe dovrebbe essere sempre eseguito per rendere sicuro il thread di dati statici. Poiché sappiamo che la parola chiave statica associa i dati dei metodi a livello di classe, quindi utilizzare il blocco su campi o metodi statici per farlo a livello di classe.

Inoltre per notare perché .class . È solo perché .classè equivalente a qualsiasi variabile statica di classe simile a:

private final static Object lock = new Object();

dove il nome della variabile di blocco è class e il tipo è Class <T>

Per saperne di più: https://howtodoinjava.com/java/multi-threading/object-vs-class-level-locking/

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.