Punto importante su volatile
:
- La sincronizzazione in Java è possibile utilizzando le parole chiave di Java
synchronized
e volatile
e serrature.
- In Java, non possiamo avere
synchronized
variabili. L'uso della synchronized
parola chiave con una variabile è illegale e comporterà un errore di compilazione. Invece di usare la synchronized
variabile in Java, puoi usare la volatile
variabile java , che istruirà i thread JVM a leggere il valore della volatile
variabile dalla memoria principale e non memorizzarla nella cache locale.
- Se una variabile non è condivisa tra più thread, non è necessario utilizzare la
volatile
parola chiave.
fonte
Esempio di utilizzo di volatile
:
public class Singleton {
private static volatile Singleton _instance; // volatile variable
public static Singleton getInstance() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
Stiamo creando pigramente istanza nel momento in cui arriva la prima richiesta.
Se non creiamo la _instance
variabile, volatile
il thread che sta creando l'istanza di Singleton
non è in grado di comunicare con l'altro thread. Quindi, se il thread A sta creando l'istanza Singleton e subito dopo la creazione, la CPU corrompe ecc., Tutti gli altri thread non saranno in grado di vedere il valore _instance
come non null e crederanno che sia ancora assegnato null.
Perché succede? Poiché i thread del lettore non eseguono alcun blocco e fino a quando il thread del writer non esce da un blocco sincronizzato, la memoria non verrà sincronizzata e il valore di _instance
non verrà aggiornato nella memoria principale. Con la parola chiave Volatile in Java, questo è gestito da Java stesso e tali aggiornamenti saranno visibili da tutti i thread del lettore.
Conclusione : la volatile
parola chiave viene utilizzata anche per comunicare il contenuto della memoria tra i thread.
Esempio di utilizzo di senza volatile:
public class Singleton{
private static Singleton _instance; //without volatile variable
public static Singleton getInstance(){
if(_instance == null){
synchronized(Singleton.class){
if(_instance == null) _instance = new Singleton();
}
}
return _instance;
}
Il codice sopra non è thread-safe. Anche se verifica nuovamente il valore dell'istanza all'interno del blocco sincronizzato (per motivi di prestazioni), il compilatore JIT può riorganizzare il bytecode in modo che il riferimento all'istanza sia impostato prima che il costruttore abbia terminato la sua esecuzione. Ciò significa che il metodo getInstance () restituisce un oggetto che potrebbe non essere stato inizializzato completamente. Per rendere il codice thread-safe, la parola chiave volatile può essere utilizzata da Java 5 per la variabile di istanza. Le variabili contrassegnate come volatili diventano visibili ad altri thread solo quando il costruttore dell'oggetto ha terminato completamente l'esecuzione.
fonte
volatile
utilizzo in Java :
Gli iteratori fail-fast sono in genere implementati utilizzando un volatile
contatore sull'oggetto elenco.
- Quando l'elenco viene aggiornato, il contatore viene incrementato.
- Quando
Iterator
viene creato un, il valore corrente del contatore viene incorporato Iterator
nell'oggetto.
- Quando
Iterator
viene eseguita un'operazione, il metodo confronta i due valori del contatore e genera a ConcurrentModificationException
se sono diversi.
L'implementazione di iteratori fail-safe è generalmente leggera. In genere si basano sulle proprietà delle strutture di dati dell'implementazione dell'elenco specifico. Non esiste un modello generale.
volatile
quella fornita con il nuovo modello di memoria Java definito in JSR 133: che quando un thread legge unavolatile
variabile vede non solo l'ultimo valore scritto su di esso da qualche altro thread, ma anche tutti gli altri scrive in altre variabili che erano visibili in quell'altro thread al momento dellavolatile
scrittura. Vedi questa risposta e questo riferimento .