Domanda

Ho visto alcuni esempi in Java dove fanno la sincronizzazione su un blocco di codice per modificare alcune variabili mentre quella variabile è stata dichiarata volatile originariamente .. L'ho visto in un esempio di classe di Singleton in cui hanno dichiarato l'istanza unica come volatile e loroSychronizzato il blocco che inizializza quell'istanza ... La mia domanda è il motivo per cui lo dichiariamo volatile mentre ci sincronizziamo, perché dobbiamo fare entrambi ??uno di loro non è sufficiente per l'altro ??

public class someClass {
volatile static uniqueInstance = null;

public static someClass getInstance() {
        if(uniqueInstance == null) {
            synchronized(someClass.class) {
                if(uniqueInstance == null) {
                    uniqueInstance = new someClass();
                }
            }
        }
        return uniqueInstance;
    }
.

Grazie in anticipo.

È stato utile?

Soluzione

La sincronizzazione da sola sarebbe sufficiente in questo caso se il primo controllo era all'interno del blocco sincronizzato (ma non è e un thread non può vedere le modifiche eseguite da un altro se la variabile non era volatile).Da solo volatile non sarebbe sufficiente perché è necessario eseguire più di un'operazione atomicamente.Ma attenzione!Quello che hai qui è il cosiddetto blocco a doppio controllo - un idioma comune, che purtroppo non funziona in modo affidabile .Penso che questo sia cambiato da Java 1.6, ma ancora questo tipo di codice potrebbe essere rischioso.

Modifica : Quando la variabile è volatile, questo codice funziona correttamente da JDK 5 (non 6 come ho scritto in precedenza), ma non funzionerà come previsto con JDK 1.4 o prima.

Altri suggerimenti

Questo utilizza il blocco a doppio controllo, si noti che il if(uniqueInstance == null) non è all'interno della parte sincronizzata.

Se uniqueInstance non è volatile, potrebbe essere "inizializzato" con un oggetto parzialmente costruito in cui le parti non sono visibili ad oltre l'esecuzione del filettatura nel blocco synchronized.Volatile rende questo un funzionamento tutto o niente in questo caso.

Se non avevi il blocco sincronizzato, potresti finire con 2 thread arrivare a questo punto allo stesso tempo.

if(uniqueInstance == null) {
      uniqueInstance = new someClass(); <---- here
.

e tu costruisci 2 oggetti someccans, che sconfiggono lo scopo.

rigorosamente parlando, non è necessario volatile, il metodo potrebbe essere stato

public static someClass getInstance() {
    synchronized(FullDictionary.class) {
         if(uniqueInstance == null) {
             uniqueInstance = new someClass();
          }
         return uniqueInstance;
    }
}
.

Ma questo incorre la sincronizzazione e la serializzazione di ogni filettatura che esegue GETTINSTANCE ().

Questo post spiega l'ideadietro volatile.

Viene anche affrontato nel lavoro seminale, concorrenza Java in pratica .

L'idea principale è che la concorrenza non solo comporta la protezione dello stato condiviso ma anche la visibilità di tale Stato tra i threads: è qui che è volatile. (Questo contratto più grande è definito da Java Memory Model .)

È possibile eseguire la sincronizzazione senza utilizzare il blocco sincronizzato. Non è necessario utilizzare la variabile volatile in esso ... Aggiorna volatile L'unica variabile dalla memoria principale. E Aggiorna sincronizzata tutte le variabili condivise che sono state accessibili dalla memoria principale. Quindi puoi usarlo in base alle tue esigenze ..

I miei due centesimi qui

frist una rapida spiegazione dell'intuizione di questo codice

if(uniqueInstance == null) {
        synchronized(someClass.class) {
            if(uniqueInstance == null) {
                uniqueInstance = new someClass();
            }
        }
    }
.

Il motivo per cui controlla uniciLIANSTANCE== NULL due volte è ridurre il sovraccarico di chiamare il blocco sincronizzato che è relativamente più lento.Il cosiddetto blocco a doppio controllo.

In secondo luogo, il motivo per cui utilizza la sincronizzazione è facile da capire, rendono le due operazioni all'interno del blocco sincronizzato atomico.

L'ultima volta il modificatore volatile garantisce che tutte le discussioni veda la stessa copia in modo che il primo controllo al di fuori del blocco sincronizzato vedrà il valore di UniqueNstance in un modo "sincronizzato" con il blocco sincronizzato.Senza il modificatore volatile, un thread può assegnare un valore all'esclusivo, ma l'altro thread potrebbe non vederlo con il primo controllo.(Anche se il secondo controllo lo vedrà)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top