A cosa serve la parola chiave volatile


Risposte:


742

volatileha una semantica per la visibilità della memoria. Fondamentalmente, il valore di un volatilecampo diventa visibile a tutti i lettori (in particolare altri thread) dopo che un'operazione di scrittura è stata completata su di esso. Senza volatile, i lettori potrebbero vedere un valore non aggiornato.

Per rispondere alla tua domanda: Sì, utilizzo una volatilevariabile per controllare se un po 'di codice continua un ciclo. Il ciclo verifica il volatilevalore e continua se lo è true. È possibile impostare la condizione falsechiamando un metodo "stop". Il ciclo vede falsee termina quando verifica il valore dopo che il metodo stop ha completato l'esecuzione.

Il libro " Java Concurrency in Practice ", di cui consiglio vivamente, fornisce una buona spiegazione volatile. Questo libro è stato scritto dalla stessa persona che ha scritto l'articolo IBM a cui fa riferimento la domanda (in effetti, cita il suo libro in fondo a quell'articolo). Il mio uso volatileè quello che il suo articolo chiama "flag di stato modello 1".

Se vuoi saperne di più su come volatilefunziona sotto il cofano, leggi il modello di memoria Java . Se vuoi andare oltre quel livello, dai un'occhiata a un buon libro sull'architettura del computer come Hennessy & Patterson e leggi sulla coerenza e coerenza della cache.


118
Questa risposta è corretta, ma incompleta. Omette un'importante proprietà di volatilequella fornita con il nuovo modello di memoria Java definito in JSR 133: che quando un thread legge una volatilevariabile 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 della volatilescrittura. Vedi questa risposta e questo riferimento .
Adam Zalcman,

46
Per i principianti, ti chiederei di dimostrare con un po 'di codice (per favore?)
Hungry Blue Dev,

6
L'articolo collegato nella domanda contiene esempi di codice.
Greg Mattes,

Penso che il collegamento 'Hennessy & Patterson' sia rotto. E il collegamento al "modello di memoria Java" porta in realtà alle specifiche del linguaggio Java di Oracle "Capitolo 17. Discussioni e blocchi".
Kris,

2
@fefrei: "immediatamente" è un termine colloquiale. Naturalmente, ciò non può essere garantito quando non sono specificati né i tempi di esecuzione né gli algoritmi di pianificazione dei thread. L'unico modo per un programma di scoprire se una lettura volatile è successiva a una particolare scrittura volatile è controllando se il valore visto è quello scritto previsto.
Holger,

177

"... il modificatore volatile garantisce che qualsiasi thread che legge un campo vedrà l'ultimo valore scritto." - Josh Bloch

Se stai pensando di usare volatile, leggi sul pacchetto java.util.concurrentche tratta del comportamento atomico.

Il post di Wikipedia su un modello Singleton mostra un uso volatile.


18
Perché c'è tanto volatilee synchronizedle parole chiave?
ptkato,

5
L'articolo di Wikipedia su un modello Singleton è cambiato molto da allora e non contiene più detto volatileesempio. Può essere trovato in una versione archiviata .
bskp,

1
@ptkato Queste due parole chiave hanno scopi completamente diversi, quindi la domanda non ha molto senso come confronto, sebbene siano entrambi correlati alla concorrenza. È come dire "Perché ci sono entrambi voide publicparole chiave".
David

134

Punto importante su volatile:

  1. La sincronizzazione in Java è possibile utilizzando le parole chiave di Java synchronizede volatilee serrature.
  2. In Java, non possiamo avere synchronizedvariabili. L'uso della synchronizedparola chiave con una variabile è illegale e comporterà un errore di compilazione. Invece di usare la synchronizedvariabile in Java, puoi usare la volatilevariabile java , che istruirà i thread JVM a leggere il valore della volatilevariabile dalla memoria principale e non memorizzarla nella cache locale.
  3. Se una variabile non è condivisa tra più thread, non è necessario utilizzare la volatileparola 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 _instancevariabile, volatileil thread che sta creando l'istanza di Singletonnon è 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 _instancecome 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 _instancenon 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 volatileparola 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

inserisci qui la descrizione dell'immagine

volatileutilizzo in Java :

Gli iteratori fail-fast sono in genere implementati utilizzando un volatilecontatore sull'oggetto elenco.

  • Quando l'elenco viene aggiornato, il contatore viene incrementato.
  • Quando Iteratorviene creato un, il valore corrente del contatore viene incorporato Iteratornell'oggetto.
  • Quando Iteratorviene eseguita un'operazione, il metodo confronta i due valori del contatore e genera a ConcurrentModificationExceptionse 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.


2
"Gli iteratori fail-fast sono in genere implementati utilizzando un contatore volatile" - non è più il caso, troppo costoso: bugs.java.com/bugdatabase/view_bug.do?bug_id=6625725
Vsevolod Golovanov

il doppio controllo per _instance è sicuro? pensavo che non fossero al sicuro nemmeno con i volatili
Dexters

"che istruirà i thread JVM a leggere il valore della variabile volatile dalla memoria principale e non memorizzarlo nella cache locale." buon punto
Humoyun Ahmad il

Per la sicurezza del filo si potrebbe anche andare avanti private static final Singleton _instance;.
Chris311,

53

volatile è molto utile per interrompere le discussioni.

Non che dovresti scrivere i tuoi thread, Java 1.6 ha molti pool di thread carini. Ma se sei sicuro di aver bisogno di un thread, dovrai sapere come fermarlo.

Il modello che uso per i thread è:

public class Foo extends Thread {

  private volatile boolean close = false;

  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

Nel segmento di codice sopra, la lettura del thread closenel ciclo while è diversa da quella che chiama close(). Senza volatile, il thread che esegue il loop potrebbe non vedere mai la modifica per chiudere.

Notare come non sia necessaria la sincronizzazione


2
Mi chiedo perché sia ​​persino necessario. Non è necessario solo se altri thread devono reagire al cambio di stato di questo thread in modo tale che la sincronizzazione dei thread sia in pericolo?
Jori,

27
@Jori, hai bisogno di volatile perché la lettura del thread si chiude nel ciclo while è diversa da quella che chiama close (). Senza volatile, il thread che esegue il loop potrebbe non vedere mai la modifica per chiudere.
Pirolistico

diresti che c'è un vantaggio tra l'arresto di un thread del genere o l'utilizzo dei metodi Thread # interrupt () e Thread # isInterrupted ()?
Ricardo Belchior,

2
@Pyrolistical - Hai mai visto il thread non vedere mai il cambiamento nella pratica? O puoi estendere l'esempio per innescare in modo affidabile quel problema? Sono curioso perché so di aver usato (e di aver visto altri usare) un codice sostanzialmente identico all'esempio ma senza la volatileparola chiave, e sembra sempre funzionare bene.
Aroth,

2
@aroth: con le JVM di oggi, puoi osservare che in pratica, anche con gli esempi più semplici, tuttavia, non puoi riprodurre in modo affidabile questo comportamento. Con applicazioni più complesse, a volte hai altre azioni con garanzie di visibilità della memoria all'interno del tuo codice che fanno sì che funzioni, il che è particolarmente pericoloso in quanto non sai perché funziona e una semplice modifica apparentemente non correlata nel codice può interrompere il tuo applicazione ...
Holger,

31

Un esempio comune per l'utilizzo volatileè l'uso di una volatile booleanvariabile come flag per terminare un thread. Se hai avviato un thread e desideri essere in grado di interromperlo in modo sicuro da un thread diverso, puoi fare in modo che il thread controlli periodicamente un flag. Per fermarlo, imposta la bandiera su true. Creando il flag volatile, puoi assicurarti che il thread che lo sta controllando vedrà che è stato impostato la prossima volta che lo controlla senza nemmeno usare un synchronizedblocco.


27

Una variabile dichiarata con volatileparola chiave, ha due qualità principali che la rendono speciale.

  1. Se abbiamo una variabile volatile, non può essere memorizzata nella cache della memoria del computer (microprocessore) da nessun thread. L'accesso avveniva sempre dalla memoria principale.

  2. Se è in corso un'operazione di scrittura su una variabile volatile e all'improvviso viene richiesta un'operazione di lettura , si garantisce che l' operazione di scrittura verrà terminata prima dell'operazione di lettura .

Due qualità sopra lo deducono

  • Tutti i thread che leggono una variabile volatile leggeranno sicuramente l'ultimo valore. Perché nessun valore memorizzato nella cache può inquinarlo. Inoltre, la richiesta di lettura verrà concessa solo dopo il completamento dell'operazione di scrittura corrente.

E d'altra parte,

  • Se analizziamo ulteriormente il numero 2 che ho citato, possiamo vedere che la volatileparola chiave è un modo ideale per mantenere una variabile condivisa che ha 'n' numero di thread del lettore e solo un thread del writer per accedervi. Una volta aggiunta la volatileparola chiave, è fatta. Nessun altro overhead sulla sicurezza del thread.

Conversly,

Non possiamo utilizzare volatileesclusivamente la parola chiave per soddisfare una variabile condivisa alla quale ha accesso più di un thread del writer .


3
Questo spiega la differenza tra volatile e sincronizzato.
ajay

13

Nessuno ha menzionato il trattamento dell'operazione di lettura e scrittura per il tipo lungo e doppio variabile. Le letture e le scritture sono operazioni atomiche per le variabili di riferimento e per la maggior parte delle variabili primitive, ad eccezione dei tipi di variabili lunghe e doppie, che devono utilizzare la parola chiave volatile per essere operazioni atomiche. @link


Per renderlo ancora più chiaro, NON È NECESSARIO impostare un valore booleano volatile, poiché la lettura e la scrittura di un booleano È GIÀ atomica.
Kai Wang,

2
@KaiWang non è necessario utilizzare volatile su valori booleani per scopi di atomicità. Ma potresti certamente per motivi di visibilità. È quello che intendevi dire?
SusanW,

12

Sì, volatile deve essere utilizzato ogni volta che si desidera accedere a una variabile mutabile da più thread. Non è un caso d'uso molto comune perché in genere è necessario eseguire più di una singola operazione atomica (ad esempio, controllare lo stato della variabile prima di modificarlo), nel qual caso si utilizzerà invece un blocco sincronizzato.


10

A mio avviso, due scenari importanti diversi dall'arresto del thread in cui viene utilizzata la parola chiave volatile sono:

  1. Meccanismo di bloccaggio doppio controllo . Utilizzato spesso nel modello di progettazione Singleton. In questo l' oggetto singleton deve essere dichiarato volatile .
  2. Risvegli spuri . A volte il thread può svegliarsi dalla chiamata in attesa anche se non è stata emessa alcuna chiamata di notifica. Questo comportamento si chiama risveglio falso. Questo può essere contrastato usando una variabile condizionale (flag booleano). Metti la chiamata wait () in un ciclo while finché il flag è vero. Quindi, se il thread si riattiva dalla chiamata di attesa a causa di motivi diversi da Notifica / Notifica, allora incontra il flag è ancora vero e quindi le chiamate aspettano di nuovo. Prima di chiamare la notifica impostare questo flag su true. In questo caso la bandiera booleana viene dichiarata volatile .

L'intera sezione # 2 sembra molto confusa, sta confondendo le notifiche perse, i risvegli spuri e i problemi di visibilità della memoria. Inoltre, se tutti gli utilizzi della bandiera sono sincronizzati, la volatile è ridondante. Penso di avere capito il tuo punto, ma il risveglio falso non è il termine corretto. Si prega di precisare.
Nathan Hughes,

5

Dovrai utilizzare una parola chiave "volatile" o "sincronizzata" e qualsiasi altro strumento e tecnica di controllo della concorrenza che potresti avere a disposizione se stai sviluppando un'applicazione multithread. Esempio di tale applicazione sono le app desktop.

Se si sta sviluppando un'applicazione che verrebbe distribuita al server delle applicazioni (Tomcat, JBoss AS, Glassfish, ecc.) Non è necessario gestire autonomamente il controllo della concorrenza come già indicato dal server delle applicazioni. In effetti, se ricordassi correttamente lo standard Java EE proibire qualsiasi controllo di concorrenza in servlet ed EJB, poiché fa parte del livello 'infrastruttura' che si suppone essere libero di gestirlo. Esegui il controllo della concorrenza in tale app solo se stai implementando oggetti singleton. Questo è già stato risolto se hai lavorato a maglia i tuoi componenti usando frameworkd come Spring.

Pertanto, nella maggior parte dei casi di sviluppo Java in cui l'applicazione è un'applicazione Web e utilizza framework IoC come Spring o EJB, non è necessario utilizzare "volatile".


5

volatilegarantisce solo che tutti i thread, anche se stessi, stanno incrementando. Ad esempio: un contatore vede contemporaneamente la stessa faccia della variabile. Non viene utilizzato al posto di sincronizzato o atomico o altre cose, rende completamente sincronizzate le letture. Si prega di non confrontarlo con altre parole chiave java. Come mostrato nell'esempio di seguito, anche le operazioni con variabili volatili sono atomiche e falliscono o hanno successo in una volta.

package io.netty.example.telnet;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static volatile  int a = 0;
    public static void main(String args[]) throws InterruptedException{

        List<Thread> list = new  ArrayList<Thread>();
        for(int i = 0 ; i<11 ;i++){
            list.add(new Pojo());
        }

        for (Thread thread : list) {
            thread.start();
        }

        Thread.sleep(20000);
        System.out.println(a);
    }
}
class Pojo extends Thread{
    int a = 10001;
    public void run() {
        while(a-->0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Main.a++;
            System.out.println("a = "+Main.a);
        }
    }
}

Anche se metti risultati volatili o no, differiranno sempre. Ma se usi AtomicInteger come sotto i risultati saranno sempre gli stessi. Lo stesso vale anche per la sincronizzazione.

    package io.netty.example.telnet;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;

    public class Main {

        public static volatile  AtomicInteger a = new AtomicInteger(0);
        public static void main(String args[]) throws InterruptedException{

            List<Thread> list = new  ArrayList<Thread>();
            for(int i = 0 ; i<11 ;i++){
                list.add(new Pojo());
            }

            for (Thread thread : list) {
                thread.start();
            }

            Thread.sleep(20000);
            System.out.println(a.get());

        }
    }
    class Pojo extends Thread{
        int a = 10001;
        public void run() {
            while(a-->0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Main.a.incrementAndGet();
                System.out.println("a = "+Main.a);
            }
        }
    }

4

Sì, lo uso parecchio: può essere molto utile per il codice multi-thread. L'articolo che hai indicato è buono. Sebbene ci siano due cose importanti da tenere a mente:

  1. Dovresti usare volatile solo se capisci completamente cosa fa e come differisce dalla sincronizzazione. In molte situazioni, volatile sembra, in superficie, un'alternativa più semplice e performante alla sincronizzazione, quando spesso una migliore comprensione della volatile chiarirebbe che la sincronizzazione è l'unica opzione che funzionerebbe.
  2. volatile in realtà non funziona in molte JVM precedenti, anche se sincronizzato. Ricordo di aver visto un documento che faceva riferimento ai vari livelli di supporto in diverse JVM ma sfortunatamente non riesco a trovarlo ora. Sicuramente esaminalo se stai usando Java pre 1.5 o se non hai il controllo sulle JVM su cui verrà eseguito il tuo programma.

4

Ogni thread che accede a un campo volatile leggerà il valore corrente prima di continuare, anziché (potenzialmente) utilizzare un valore memorizzato nella cache.

Solo la variabile membro può essere volatile o transitoria.


3

Assolutamente si. (E non solo in Java, ma anche in C #.) Ci sono volte in cui è necessario ottenere o impostare un valore che è garantito per essere un'operazione atomica sulla propria piattaforma, un int o un valore booleano, ad esempio, ma non è necessario il sovraccarico del blocco del filo. La parola chiave volatile ti consente di assicurarti che quando leggi il valore ottieni il valore corrente e non un valore memorizzato nella cache che è stato appena reso obsoleto da una scrittura su un altro thread.


3

Esistono due diversi usi della parola chiave volatile.

  1. Impedisce a JVM di leggere i valori dal registro (si assume come cache) e impone che il suo valore venga letto dalla memoria.
  2. Riduce il rischio di errori di coerenza della memoria.

Impedisce a JVM di leggere i valori nel registro e impone che il suo valore venga letto dalla memoria.

Un flag di occupato viene utilizzato per impedire che un thread continui mentre il dispositivo è occupato e il flag non è protetto da un lucchetto:

while (busy) {
    /* do something else */
}

Il thread di test continuerà quando un altro thread disattiva il flag di occupato :

busy = 0;

Tuttavia, poiché si accede frequentemente a occupato nel thread di test, JVM può ottimizzare il test posizionando il valore di occupato in un registro, quindi testare il contenuto del registro senza leggere il valore di occupato in memoria prima di ogni test. Il thread di test non vedrebbe mai il cambiamento di occupato e l'altro thread cambierebbe solo il valore di occupato in memoria, con conseguente deadlock. Dichiarare la bandiera occupata come volatile forza il suo valore da leggere prima di ogni test.

Riduce il rischio di errori di coerenza della memoria.

L'uso di variabili volatili riduce il rischio di errori di coerenza della memoria , poiché qualsiasi scrittura su una variabile volatile stabilisce una relazione "accada prima" con letture successive della stessa variabile. Ciò significa che le modifiche a una variabile volatile sono sempre visibili ad altri thread.

La tecnica di leggere, scrivere senza errori di coerenza della memoria è chiamata azione atomica .

Un'azione atomica è un'azione che si verifica effettivamente in una volta. Un'azione atomica non può fermarsi nel mezzo: o accade completamente o non accade affatto. Non sono visibili effetti collaterali di un'azione atomica fino al completamento dell'azione.

Di seguito sono riportate le azioni che puoi specificare che sono atomiche:

  • Letture e scritture sono atomiche per le variabili di riferimento e per la maggior parte delle variabili primitive (tutti i tipi tranne long e double).
  • Le letture e le scritture sono atomiche per tutte le variabili dichiarate volatili (comprese le variabili lunghe e doppie).

Saluti!


3

volatiledice per un programmatore che il valore sarà sempre aggiornato. Il problema è che il valore può essere salvato su diversi tipi di memoria hardware. Ad esempio, possono essere registri CPU, cache CPU, RAM ... I registri CPU e CPU appartengono alla CPU e non possono condividere dati diversi dalla RAM che si trovano in soccorso in ambiente multithreading

inserisci qui la descrizione dell'immagine

volatileparola chiave dice che una variabile verrà letto e scritto da / per la memoria RAM direttamente . Ha una certa impronta computazionale

Java 5esteso volatilesupportando happens-before[Informazioni]

Si verifica una scrittura su un campo volatile prima di ogni successiva lettura di quel campo.

volatilela parola chiave non risolve una race conditionsituazione in cui più thread possono scrivere contemporaneamente alcuni valori. La risposta è la synchronizedparola chiave [Informazioni]

Di conseguenza, è sicuro solo quando un thread scrive e altri leggono semplicemente il volatilevalore

volatile vs sincronizzato


2

Volatile segue.

1> Lettura e scrittura di variabili volatili da parte di thread diversi sono sempre dalla memoria, non dalla cache del thread o dal registro CPU. Quindi ogni thread si occupa sempre dell'ultimo valore. 2> Quando 2 thread diversi lavorano con la stessa istanza o variabili statiche nell'heap, uno può vedere le azioni dell'altro come fuori servizio. Vedi il blog di jeremy manson su questo. Ma volatile aiuta qui.

Il seguente codice completamente in esecuzione mostra come un numero di thread può essere eseguito in ordine predefinito e stampare output senza utilizzare la parola chiave sincronizzata.

thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3

Per raggiungere questo obiettivo, possiamo utilizzare il seguente codice di esecuzione completo.

public class Solution {
    static volatile int counter = 0;
    static int print = 0;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread[] ths = new Thread[4];
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(new MyRunnable(i, ths.length));
            ths[i].start();
        }
    }
    static class MyRunnable implements Runnable {
        final int thID;
        final int total;
        public MyRunnable(int id, int total) {
            thID = id;
            this.total = total;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                if (thID == counter) {
                    System.out.println("thread " + thID + " prints " + print);
                    print++;
                    if (print == total)
                        print = 0;
                    counter++;
                    if (counter == total)
                        counter = 0;
                } else {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // log it
                    }
                }
            }
        }
    }
}

Il seguente link github ha un file Leggimi, che fornisce una spiegazione adeguata. https://github.com/sankar4git/volatile_thread_ordering


1

Dalla pagina della documentazione di Oracle , sorge la necessità di una variabile volatile per risolvere i problemi di coerenza della memoria:

L'uso di variabili volatili riduce il rischio di errori di coerenza della memoria, poiché qualsiasi scrittura su una variabile volatile stabilisce una relazione accidentale prima delle successive letture della stessa variabile.

Ciò significa che le modifiche a una volatilevariabile sono sempre visibili ad altri thread. Significa anche che quando un thread legge una variabile volatile, non vede solo l'ultima modifica avolatile , ma anche gli effetti collaterali del codice che ha portato alla modifica.

Come spiegato in Peter Parkerrisposta, in assenza di volatilemodificatore, lo stack di ogni thread può avere la propria copia della variabile. Rendendo la variabile comevolatile , i problemi di coerenza della memoria sono stati risolti.

Dai un'occhiata alla pagina tutorial di jenkov per una migliore comprensione.

Dai un'occhiata alla relativa domanda SE per maggiori dettagli sui casi volatili e di utilizzo per usare volatili:

Differenza tra volatile e sincronizzata in Java

Un caso d'uso pratico:

Avete molte discussioni, che hanno bisogno di stampare l'ora corrente a un particolare formato, ad esempio: java.text.SimpleDateFormat("HH-mm-ss"). Yon può avere una classe, che converte l'ora corrente in SimpleDateFormate aggiorna la variabile per ogni secondo. Tutti gli altri thread possono semplicemente utilizzare questa variabile volatile per stampare l'ora corrente nei file di registro.


1

Le variabili volatili sono una sincronizzazione leggera. Quando è richiesta la visibilità degli ultimi dati tra tutti i thread e l'atomicità può essere compromessa, in tali situazioni è necessario preferire le variabili volatili. La lettura delle variabili volatili restituisce sempre la scrittura più recente eseguita da qualsiasi thread poiché non sono memorizzate nella cache né nei registri né nelle cache in cui altri processori non possono vedere. Volatile è Lock-Free. Uso volatile, quando lo scenario soddisfa i criteri di cui sopra.


-1

La chiave volatile quando usata con una variabile, farà in modo che i thread che leggono questa variabile vedano lo stesso valore. Ora se hai più thread che leggono e scrivono su una variabile, rendere la variabile volatile non sarà sufficiente e i dati saranno danneggiati. I thread di immagini hanno letto lo stesso valore ma ognuno ha eseguito alcuni chase (diciamo un contatore incrementato), quando si riscrive in memoria, l'integrità dei dati viene violata. Ecco perché è necessario sincronizzare la variabile (sono possibili diverse modalità)

Se le modifiche sono fatte da 1 thread e gli altri devono solo leggere questo valore, la volatile sarà adatta.


-1

la variabile volatile viene sostanzialmente utilizzata per l'aggiornamento istantaneo (flush) nella riga principale della cache condivisa dopo l'aggiornamento, in modo che le modifiche vengano immediatamente riflesse su tutti i thread di lavoro.


-2

Di seguito è riportato un codice molto semplice per dimostrare il requisito di volatileper la variabile che viene utilizzato per controllare l'esecuzione del thread da un altro thread (questo è uno scenario in cui volatileè richiesto).

// Code to prove importance of 'volatile' when state of one thread is being mutated from another thread.
// Try running this class with and without 'volatile' for 'state' property of Task class.
public class VolatileTest {
    public static void main(String[] a) throws Exception {
        Task task = new Task();
        new Thread(task).start();

        Thread.sleep(500);
        long stoppedOn = System.nanoTime();

        task.stop(); // -----> do this to stop the thread

        System.out.println("Stopping on: " + stoppedOn);
    }
}

class Task implements Runnable {
    // Try running with and without 'volatile' here
    private volatile boolean state = true;
    private int i = 0;

    public void stop() {
        state = false;
    } 

    @Override
    public void run() {
        while(state) {
            i++;
        }
        System.out.println(i + "> Stopped on: " + System.nanoTime());
    }
}

Quando volatilenon viene utilizzato: non verrà mai visualizzato il messaggio " Interrotto: xxx " anche dopo " Interruzione: xxx " e il programma continua a essere eseguito.

Stopping on: 1895303906650500

Se volatileutilizzato: vedrai immediatamente " Interrotto: xxx ".

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

Demo: https://repl.it/repls/SilverAgonizingObjectcode


Al downvoter: cura di spiegare perché il downvote? Se questo non è vero, almeno imparerò cosa c'è che non va. Ho aggiunto questo stesso commento due volte, ma non so chi
cancellerà

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.