logo

Parola chiave volatile in Java

La parola chiave volatile viene utilizzata per modificare il valore di una variabile da thread diversi. Viene anche utilizzato per rendere le classi thread-safe. Ciò significa che più thread possono utilizzare un metodo e un'istanza delle classi contemporaneamente senza alcun problema. La parola chiave volatile può essere utilizzata sia con il tipo primitivo che con gli oggetti.

La parola chiave volatile non memorizza nella cache il valore della variabile e legge sempre la variabile dalla memoria principale. La parola chiave volatile non può essere utilizzata con classi o metodi. Tuttavia, viene utilizzato con le variabili. Garantisce inoltre visibilità e ordinamento. Impedisce al compilatore di riordinare il codice.

Il contenuto del particolare registro del dispositivo potrebbe cambiare in qualsiasi momento, quindi è necessaria la parola chiave volatile per garantire che tali accessi non vengano ottimizzati dal compilatore.

Esempio

 class Test { static int var=5; } 

Nell'esempio precedente, supponiamo che due thread stiano lavorando sulla stessa classe. Entrambi i thread vengono eseguiti su processori diversi in cui ogni thread ha la propria copia locale di var. Se un thread modifica il suo valore, la modifica non si rifletterà in quello originale nella memoria principale. Porta a un'incoerenza dei dati perché l'altro thread non è a conoscenza del valore modificato.

 class Test { static volatile int var =5; } 

Nell'esempio precedente, le variabili statiche sono membri della classe condivisi tra tutti gli oggetti. C'è solo una copia nella memoria principale. Il valore di una variabile volatile non verrà mai archiviato nella cache. Tutte le operazioni di lettura e scrittura verranno eseguite da e verso la memoria principale.

Quando usarlo?

  • È possibile utilizzare una variabile volatile se si desidera leggere e scrivere automaticamente una variabile lunga e doppia.
  • Può essere utilizzato come metodo alternativo per ottenere la sincronizzazione in Java.
  • Tutti i thread del lettore vedranno il valore aggiornato della variabile volatile dopo aver completato l'operazione di scrittura. Se non stai utilizzando la parola chiave volatile, thread di lettori diversi potrebbero visualizzare valori diversi.
  • Viene utilizzato per informare il compilatore che più thread accederanno a una particolare istruzione. Impedisce al compilatore di eseguire qualsiasi riordino o ottimizzazione.
  • Se non si utilizza il compilatore di variabili volatili è possibile riordinare il codice, liberamente di scrivere nella cache il valore della variabile volatile invece di leggerlo dalla memoria principale.

Punti importanti

  • Puoi utilizzare la parola chiave volatile con le variabili. L'uso di parole chiave volatili con classi e metodi è illegale.
  • Garantisce che il valore della variabile volatile verrà sempre letto dalla memoria principale, non dalla cache dei thread locali.
  • Se hai dichiarato la variabile come volatile, Lettura e Scrittura sono atomiche
  • Riduce il rischio di errori di coerenza della memoria.
  • Qualsiasi scrittura su variabile volatile in Java stabilisce un evento prima della relazione con le letture successive della stessa variabile.
  • Le variabili volatili sono sempre visibili agli altri thread.
  • La variabile volatile che è un riferimento a un oggetto può essere nulla.
  • Quando una variabile non è condivisa tra più thread, non è necessario utilizzare la parola chiave volatile con quella variabile.

Differenza tra sincronizzazione e parola chiave volatile

La parola chiave volatile non sostituisce la parola chiave sincronizzata, ma in alcuni casi può essere utilizzata come alternativa. Ci sono le seguenti differenze:

Parola chiave volatile Parola chiave di sincronizzazione
La parola chiave volatile è un modificatore di campo. La parola chiave sincronizzata modifica blocchi di codice e metodi.
Il thread non può essere bloccato per l'attesa in caso di volatile. I thread possono essere bloccati in attesa in caso di sincronizzazione.
Migliora le prestazioni del thread. I metodi sincronizzati riducono le prestazioni del thread.
Sincronizza il valore di una variabile alla volta tra la memoria thread e la memoria principale. Sincronizza il valore di tutte le variabili tra la memoria thread e la memoria principale.
I campi volatili non sono soggetti all'ottimizzazione del compilatore. La sincronizzazione è soggetta all'ottimizzazione del compilatore.

Esempio di parola chiave volatile

Nell'esempio seguente abbiamo definito una classe che aumenta il valore del contatore. Il metodo run() in VolatileThread.java ottiene il valore aggiornato e il vecchio valore quando il thread inizia l'esecuzione. Nella classe principale definiamo l'array di thread.

VolatileData.java

 public class VolatileData { private volatile int counter = 0; public int getCounter() { return counter; } public void increaseCounter() { ++counter; //increases the value of counter by 1 } } 

VolatileThread.java

 VolatileThread.java public class VolatileThread extends Thread { private final VolatileData data; public VolatileThread(VolatileData data) { this.data = data; } @Override public void run() { int oldValue = data.getCounter(); System.out.println('[Thread ' + Thread.currentThread().getId() + ']: Old value = ' + oldValue); data.increaseCounter(); int newValue = data.getCounter(); System.out.println('[Thread ' + Thread.currentThread().getId() + ']: New value = ' + newValue); } } 

VolatileMain.java

 public class VolatileMain { private final static int noOfThreads = 2; public static void main(String[] args) throws InterruptedException { VolatileData volatileData = new VolatileData(); //object of VolatileData class Thread[] threads = new Thread[noOfThreads]; //creating Thread array for(int i = 0; i <noofthreads; ++i) threads[i]="new" volatilethread(volatiledata); for(int i="0;" < noofthreads; threads[i].start(); starts all reader threads threads[i].join(); wait for } pre> <p> <strong>Output:</strong> </p> <pre> [Thread 9]: Old value = 0 [Thread 9]: New value = 1 [Thread 10]: Old value = 1 [Thread 10]: New value = 2 </pre> <hr></noofthreads;>