Volatile vs Statico in Java


Risposte:


365

Dichiarare una variabile statica in Java significa che ci sarà una sola copia, indipendentemente dal numero di oggetti della classe creati. La variabile sarà accessibile anche senza alcuna Objectscreazione. Tuttavia, i thread possono avere valori memorizzati nella cache locale.

Quando una variabile è volatile e non statica , ci sarà una variabile per ciascuna Object. Quindi, in superficie sembra che non ci sia differenza da una variabile normale ma totalmente diversa da statica . Tuttavia, anche con i Objectcampi, un thread può memorizzare nella cache un valore variabile localmente.

Ciò significa che se due thread aggiornano contemporaneamente una variabile dello stesso oggetto e la variabile non viene dichiarata volatile, potrebbe esserci un caso in cui uno dei thread ha nella cache un vecchio valore.

Anche se accedi a un valore statico attraverso più thread, ogni thread può avere la sua copia cache locale! Per evitare ciò, puoi dichiarare la variabile come volatile statica e questo costringerà il thread a leggere ogni volta il valore globale.

Tuttavia, volatile non sostituisce la corretta sincronizzazione!
Per esempio:

private static volatile int counter = 0;

private void concurrentMethodWrong() {
  counter = counter + 5;
  //do something
  counter = counter - 5;
}

Eseguire concurrentMethodWrongcontemporaneamente più volte può portare a un valore finale del contatore diverso da zero!
Per risolvere il problema, devi implementare un blocco:

private static final Object counterLock = new Object();

private static volatile int counter = 0;

private void concurrentMethodRight() {
  synchronized (counterLock) {
    counter = counter + 5;
  }
  //do something
  synchronized (counterLock) {
    counter = counter - 5;
  }
}

O usa la AtomicIntegerclasse.


7
Il modificatore volatile garantisce che qualsiasi thread che legge un campo vedrà l'ultimo valore scritto, quindi è necessario se la variabile è condivisa tra più thread e hai bisogno di questa funzione, dipende dal tuo caso d'uso.
stivlo

5
Qual è la cache quando si dice "memorizzato nella cache locale"? Cache CPU, una specie di cache JVM?
Mert inan,

6
@mertinan sì, la variabile può trovarsi in una cache più vicina al processore o al core. Vedi cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html per maggiori dettagli.
stivlo,

15
'volatile' non implica 'una variabile per oggetto'. L'assenza di "statico" lo fa. -1 per non aver chiarito questo malinteso elementare da parte del PO.
Marchese di Lorne,

27
@EJP Ho pensato che la frase "Dichiarando una variabile come volatile, ci sarà una variabile per ogni oggetto. Quindi in superficie sembra che non ci sia differenza da una variabile normale" stava spiegando che, ho aggiunto e non statico , sentiti libero di modificare l'articolo e migliorare la formulazione per renderlo più chiaro.
stivlo,

288

Differenza tra statico e volatile:

Variabile statica : se due thread (supponiamo t1e t2) accedono allo stesso oggetto e aggiornano una variabile dichiarata come statica, significa t1che t2possono creare la propria copia locale dello stesso oggetto (comprese le variabili statiche) nella rispettiva cache, quindi aggiorna creato dalla t1variabile statica nella sua cache locale non si rifletterà nella variabile statica per la t2cache.

Le variabili statiche vengono utilizzate nel contesto di Object in cui l'aggiornamento effettuato da un oggetto si rifletterebbe in tutti gli altri oggetti della stessa classe, ma non nel contesto di Thread in cui l'aggiornamento di un thread alla variabile statica rifletterà immediatamente le modifiche a tutti i thread (nella loro cache locale).

Variabile volatile : se due thread (supponiamo t1e t2) accedono allo stesso oggetto e aggiornano una variabile dichiarata come volatile, ciò significa t1che t2può creare la propria cache locale dell'oggetto tranne la variabile dichiarata come volatile . Quindi la variabile volatile avrà solo una copia principale che verrà aggiornata da thread diversi e l'aggiornamento effettuato da un thread alla variabile volatile si rifletterà immediatamente sull'altro thread.


6
Ciao @Som, per favore correggimi se sbaglio. Ma non pensate che l'istruzione " ma non nel contesto di Thread in cui l'aggiornamento di un thread alla variabile statica rifletterà immediatamente le modifiche a tutti i thread (nella loro cache locale). " Dovrebbe essere "ma non nel contesto di Thread in cui l'aggiornamento di un thread alla variabile statica <<NOT>> rifletterà immediatamente le modifiche a tutti i thread (nella loro cache locale). "
Jaikrat,

@Jaikrat Sì, è stato molto confuso per me. La mia comprensione è che hai ragione e che questa risposta è sbagliata, come scritto. Vorrei anche essere corretto se sbaglio.
stuart

@Jaikrat I thread non memorizzano nella cache le variabili statiche ma fanno riferimento alle variabili statiche aggiornate.
Som

@Som Quindi desideri correggere il para e rimuovere ma non nel contesto di Thread . È molto confuso. Grazie
Jaikrat il

Purtroppo questa risposta non è corretta. Nelle CPU moderne, anche una volatilevariabile può essere condivisa tra cache CPU distinte. Ciò non presenta alcun problema poiché la cache negozia la proprietà esclusiva della linea di cache prima di modificarla.
David Schwartz,

32

Oltre ad altre risposte, vorrei aggiungere un'immagine per essa (la foto semplifica la comprensione)

inserisci qui la descrizione dell'immagine

staticle variabili possono essere memorizzate nella cache per singoli thread. In un ambiente multi-thread se un thread modifica i suoi dati memorizzati nella cache, ciò potrebbe non riflettere per altri thread in quanto ne hanno una copia .

volatiledichiarazione assicura che i thread non memorizzino nella cache i dati e utilizza solo la copia condivisa .

fonte dell'immagine


1
le variabili statiche sono condivise tra gli oggetti in un thread? Questo dovrebbe leggere le variabili statiche condivise tra gli oggetti tutti gli oggetti indipendentemente dai thread.
cquezel,

1
"Le variabili volatili sono condivise tra più thread (quindi anche gli oggetti)." Volatile non cambia il modo in cui le variabili sono condivise tra più thread o oggetti. Cambia il modo in cui il runtime è autorizzato a memorizzare nella cache il valore.
cquezel,

1
Il tuo commento sulle variabili statiche si applica anche a non statico e "verrà memorizzato nella cache" e "non rifletterà" dovrebbe probabilmente essere riformulato "potrebbe essere memorizzato nella cache" e "potrebbe non riflettere".
cquezel,

4
Ero molto confuso. questa immagine ha chiarito tutte le mie domande!
vins

5

Penso statice volatilenon ho alcuna relazione. Ti suggerisco di leggere il tutorial Java per comprendere Atomic Access e perché usare l'accesso atomico, capire cosa è intercalato , troverai la risposta.


4

In parole povere,

  1. statico : le staticvariabili sono associate alla classe , piuttosto che a qualsiasi oggetto . Ogni istanza della classe condivide una variabile di classe, che si trova in una posizione fissa in memoria

  2. volatile : questa parola chiave è applicabile a variabili di classe e di istanza .

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 variabile volatile sono sempre visibili ad altri thread

Date un'occhiata a questo articolo per Javin Paul capire le variabili volatili in un modo migliore.

inserisci qui la descrizione dell'immagine

In assenza di volatileparola chiave, il valore della variabile nello stack di ogni thread potrebbe essere diverso. Rendendo la variabile come volatile, tutti i thread avranno lo stesso valore nella loro memoria di lavoro e sono stati evitati errori di coerenza della memoria.

Qui il termine variablepuò essere staticvariabile (classe) o variabile instance(oggetto).

Per quanto riguarda la tua richiesta:

Ad ogni modo un valore variabile statico sarà anche un valore per tutti i thread, quindi perché dovremmo scegliere volatile?

Se ho bisogno di una instancevariabile nella mia applicazione, non posso usare la staticvariabile. Anche in caso di staticvariabili, la coerenza non è garantita a causa della cache dei thread, come mostrato nel diagramma.

L'uso delle volatilevariabili 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 variabile volatile sono sempre visibili ad altri thread.

Inoltre, significa che quando un thread legge una variabile volatile, vede non solo l'ultima modifica alla volatile, ma anche gli effetti collaterali del codice che ha portato alla modifica => gli errori di coerenza della memoria sono ancora possibili con le variabili volatili . Per evitare effetti collaterali, è necessario utilizzare variabili sincronizzate. Ma c'è una soluzione migliore in Java.

L'uso dell'accesso semplice alle variabili atomiche è più efficiente dell'accesso a queste variabili tramite codice sincronizzato

Alcune delle classi nel java.util.concurrentpacchetto forniscono metodi atomici che non si basano sulla sincronizzazione.

Fare riferimento a questo articolo di controllo della concorrenza di alto livello per maggiori dettagli.

Soprattutto dai un'occhiata alle variabili atomiche .

Domande SE correlate:

Volatile Vs Atomic

Volatile booleano vs AtomicBoolean

Differenza tra volatile e sincronizzato in Java


Apprezzo molto questa risposta. Sapevo qual è la volatileprima, ma questa risposta mi chiarisce molto perché devo ancora utilizzare volatilela staticvariabile.
Chaklader Asfak Arefe,

volatile: questa parola chiave è applicabile a variabili di classe e di istanza. L'affermazione che hai detto sopra è errata per quanto riguarda applicabile alla classe. solo due parole chiave applicabili a variabile sono volatili e transitorie. così volatile non applicabile per la classe.
ASR,

volatile è applicabile alle variabili di classe (statiche). Controlla i link singleton con doppio blocco su Google e puoi scoprire che la tua comprensione è sbagliata. stackoverflow.com/questions/18093735/…
Ravindra babu

volatile statico privato è una dichiarazione valida.
Ravindra babu,

0

l'accesso al valore variabile volatile sarà diretto dalla memoria principale. Dovrebbe essere usato solo in ambiente multi-threading. la variabile statica verrà caricata una volta. Se viene utilizzato nell'ambiente a thread singolo, anche se la copia della variabile verrà aggiornata e non vi sarà alcun danno accedendole in quanto esiste un solo thread.

Ora, se la variabile statica viene utilizzata nell'ambiente multi-threading, allora ci saranno problemi se ci si aspetta il risultato desiderato da essa. Poiché ogni thread ha la propria copia, qualsiasi incremento o decremento sulla variabile statica da un thread potrebbe non riflettere in un altro thread.

se uno si aspetta i risultati desiderati dalla variabile statica, usa volatile con statico in multi-threading, quindi tutto sarà risolto.


0

Non sono sicuro che le variabili statiche siano memorizzate nella cache nella memoria locale del thread o NOT. Ma quando ho eseguito due thread (T1, T2) accedendo allo stesso oggetto (obj) e quando l'aggiornamento è stato effettuato dal thread T1 alla variabile statica, si è riflesso in T2.


-2

Se dichiariamo una variabile come statica, ci sarà una sola copia della variabile. Quindi, ogni volta che thread diversi accedono a quella variabile, ci sarà un solo valore finale per la variabile (poiché c'è solo una posizione di memoria allocata per la variabile).

Se una variabile viene dichiarata come volatile, tutti i thread avranno la propria copia della variabile ma il valore viene preso dalla memoria principale, quindi il valore della variabile in tutti i thread sarà lo stesso.

Quindi, in entrambi i casi, il punto principale è che il valore della variabile è lo stesso in tutti i thread.


15
Se una variabile viene dichiarata come volatile, tutti i thread avranno la propria copia della variabile ma il valore viene preso dalla memoria principale. => destra. Quindi, il valore della variabile in tutti i thread sarà lo stesso. => sbagliato, ogni thread utilizzerà lo stesso valore per lo stesso oggetto, ma ogni oggetto avrà la propria copia.
stivlo,
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.