Qual è la differenza tra un metodo sincronizzato e un blocco sincronizzato in Java?

Qual è la differenza tra un metodo sincronizzato e un blocco sincronizzato in Java?

Ho cercato la risposta in Rete, la gente sembra essere così incerta su questo 🙁

La mia opinione sarebbe che non vi è alcuna differenza tra i due, tranne che il blocco di sincronizzazione potrebbe essere più localizzato in ambito e quindi il blocco sarà di minor tempo ??

E in caso di blocco su un metodo statico, su che cosa è presa la serratura? Qual è il significato di un Lock on Class?

Un metodo sincronizzato usa il ricevitore del metodo come un blocco (cioè this per i metodi non statici e la class di inclusione per i metodi statici). Synchronized blocchi Synchronized usano l’espressione come un blocco.

Quindi i seguenti due metodi sono equivalenti dal potenziale di chiusura:

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

Per i metodi statici, la class sarà bloccata:

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

Per i blocchi sincronizzati, puoi utilizzare qualsiasi object non null come blocco:

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

Lock scope

Per i metodi sincronizzati, il blocco verrà mantenuto nell’intero ambito del metodo, mentre nel blocco synchronized , il blocco verrà mantenuto solo durante lo scope di quel blocco (altrimenti noto come sezione critica). In pratica, la JVM può ottimizzare rimuovendo alcune operazioni dall’esecuzione del blocco synchronized se può dimostrare che può essere fatto in modo sicuro.

Un metodo sincronizzato è una scorciatoia. Questo:

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

è, a tutti gli effetti, equivalente a questo:

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

(Dove Something.class è l’object di class per la class Something .)

Quindi, in effetti, con un blocco sincronizzato, puoi essere più specifico sul tuo lucchetto, e più a grana fine quando vuoi usarlo, ma a parte questo non c’è differenza.

Sì, questa è una differenza. L’altro è che è ansible acquisire un blocco su altri oggetti oltre a this .

La differenza chiave è questa: se dichiari un metodo per essere sincronizzato, allora l’intero corpo del metodo diventa sincronizzato; se si utilizza il blocco sincronizzato, tuttavia, è ansible circondare solo la “sezione critica” del metodo nel blocco sincronizzato, lasciando il resto del metodo fuori dal blocco.

Se l’intero metodo fa parte della sezione critica, allora non c’è alcuna differenza. Se questo non è il caso, dovresti usare un blocco sincronizzato attorno alla sezione critica. Più affermazioni hai in un blocco sincronizzato, minore è il parallelismo generale che ottieni, quindi vuoi mantenerle al minimo.

Un metodo sincronizzato blocca l’istanza dell’object in cui è contenuto il metodo.

Dove un blocco sincronizzato può bloccare qualsiasi object, in genere un object mutex definito come variabile di istanza. Ciò consente un maggiore controllo su quali blocchi sono in funzione.

La mia opinione sarebbe che non vi è alcuna differenza tra i due, tranne che il blocco di sincronizzazione potrebbe essere più localizzato in ambito e quindi il blocco sarà di minor tempo ??

Sì. Hai ragione. A differenza dei metodi synchronized , le istruzioni sincronizzate devono specificare l’object che fornisce il blocco intrinseco.

Esempio dal tutorial di java:

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

Le istruzioni sincronizzate sono anche utili per migliorare la concorrenza con la sincronizzazione a grana fine. Puoi trovare un buon esempio nella stessa pagina di esercitazione per il caso d’uso successivo.

Supponiamo, ad esempio, che la class MsLunch abbia due campi di istanza, c1 e c2, che non vengono mai usati insieme. Tutti gli aggiornamenti di questi campi devono essere synchronized , ma non c’è motivo di impedire che un aggiornamento di c1 venga intercalato con un aggiornamento di c2, e così facendo si riduce la concorrenza creando blocchi non necessari. Invece di utilizzare metodi sincronizzati o utilizzare in altro modo il blocco associato a questo, creiamo due oggetti esclusivamente per fornire i blocchi .

E in caso di blocco su un metodo statico, su che cosa è presa la serratura? Qual è il significato di un Lock on Class?

In questo caso, il thread acquisisce il blocco intrinseco per l’object Class associato alla class. Pertanto l’accesso ai campi statici della class è controllato da un blocco che è diverso dal blocco per qualsiasi istanza della class.

Quando si effettua un metodo come sincronizzato (non static ):

Non è ansible invocare due invocazioni di metodi synchronized sullo stesso object. Quando un thread sta eseguendo un metodo sincronizzato per un object, tutti gli altri thread che invocano metodi sincronizzati per lo stesso blocco object (sospendi l’esecuzione) finché il primo thread non viene eseguito con l’object.

Se si esegue un metodo come static synchronized :

Non è ansible invocare due invocazioni di metodi static synchronized su oggetti diversi della stessa class. Quando un thread sta eseguendo un metodo static synchronized per un object di Classe A, tutti gli altri thread che invocano metodi static synchronized su qualsiasi object del blocco Classe A (sospendi l’esecuzione) finché il primo thread non viene eseguito con l’esecuzione del metodo.

Trovate alternative migliori alla sincronizzazione in questa domanda SE:

Evitare sincronizzato (questo) in Java?