5 Domanda: Variabile volatile in Java

domanda creata a Thu, Dec 17, 2015 12:00 AM

Quindi sto leggendo questo libro intitolato Java Concurrency in Practice e sono fermo su questa spiegazione che non riesco a comprendere senza un esempio. Questa è la citazione:

  

Quando il thread A scrive su un volatile   variabile e successivamente thread B   legge quella stessa variabile, i valori   di tutte le variabili che erano visibili a    A prima di scrivere su volatile   variabile diventa visibile dopo B   leggendo la variabile volatile.

Qualcuno può darmi un controesempio del perché "i valori di TUTTE le variabili che erano visibili a A prima di scrivere sulla variabile volatile diventano visibili a B AFTER dopo aver letto la variabile volatile"?

Sono confuso perché tutte le altre variabili non volatili non diventano visibili a B prima di leggere la variabile volatile?

    
20
  1. Java Concurrency in Practice è un libro fantastico. Ogni programmatore java dovrebbe leggerlo!
    2011-06-07 01: 25: 45Z
  2. per dirla semplicemente: la semantica volatile sta ordinando garanzie, quindi se qualcosa accade prima dell'operazione al volatile (leggi /scrivi) sarebbe anche leggere /scritto prima dell'operazione, seguendo efficacemente lo stesso ordine delle operazioni. Altri, i compilatori e le CPU possono eseguire operazioni di lettura /scrittura e di esecuzione in ordine per migliorare significativamente le prestazioni.
    2011-06-07 07: 37: 32Z
  3. Dai un'occhiata a esempi e spiegazioni qui: stackoverflow.com/questions/10620680/...
    2013-10-14 08: 28: 52Z
5 risposte                              5                         

La discussione B potrebbe avere una cache locale della CPU di tali variabili. Una lettura di una variabile volatile assicura che venga rilevato qualsiasi svuotamento della cache intermedia da una precedente scrittura al volatile.

Per un esempio, leggi il seguente link, che si conclude con "Correzione del blocco con doppio controllo utilizzando Volatile":

http://www.cs.umd.edu/~pugh/java/memoryModel /DoubleCheckedLocking.html

    
15
2011-06-07 16: 52: 26Z
  1. quindi stai dicendo che quando un thread legge una variabile VOLATILE, svuota anche la cache per tutte le altre variabili?
    2011-06-07 01: 34: 16Z
  2. corretto. Java definisce volatile tale che una lettura volatile di una variabile ha gli stessi effetti di memoria di un inizio sincronizzato, e una scrittura volatile della stessa variabile ha gli stessi effetti di memoria di un finale sincronizzato. In altre parole "if (volatile-read) {do-work; volatile-write}" è come un blocco sincronizzato che consente a più thread di eseguire il lavoro allo stesso tempo.
    2011-06-07 02: 17: 57Z
  3. letture volatili non svuotano le cache ... (hanno solo letto senza riordino)
    2011-06-07 07: 17: 41Z
  4. @ denniss, no non svuota la cache, lo svuotamento della cache viene eseguito da protocollo di coerenza della cache ed è livello hardware. Generalmente qualsiasi scrittura su una linea di cache trattenuta dal processore verrà aggiornata (di solito non svuotata) da qualsiasi scrittura sulla stessa riga di cache da un altro processore. Mem. Javail modello ory non rispetta precisamente alcun modello di memoria hardware, la maggior parte dei modelli è più debole. (alcuni link infoq.com/presentations/click-crash-course-modern -hardware con un eccellente video su java e hardware)
    2011-06-07 07: 30: 41Z
  5. @ dennis, dopo aver scritto sulla variabile variabile volatile A emette un errore di memoria, quindi tutto ciò che viene scritto viene svuotato. Dal momento che B legge in qualche modo l'ordine inverso prima volatile, quindi riposano, sono coerenti. Senza le regole di ordinazione, entrambi i thread sono autorizzati a qualsiasi lettura /scrittura fuori ordine. Questo è ciò che accade fondamentalmente a livello hardware (non mi discosto più dalle specifiche Java) ma l'affermazione che le cache sono scaricate non riflette la realtà. Tali cose causerebbero un degrado delle prestazioni pari a 100 volte.
    2011-06-07 07: 57: 41Z

Dichiarare una variabile Java volatile significa:

  • Il valore di questa variabile non verrà mai memorizzato nella cache locale: tutte le letture e le scritture andranno direttamente alla "memoria principale".
  • L'accesso alla variabile agisce come se fosse racchiuso in un blocco sincronizzato, sincronizzato su se stesso.

Solo per riferimento, quando è necessaria la volatilità?

  

Quando più thread utilizzano lo stesso   variabile, ogni thread avrà il suo   proprio copia della cache locale per quello   variabile. Quindi, quando aggiorna il   valore, è in realtà aggiornato nel   cache locale non nella variabile principale   memoria. L'altro thread che è   usare la stessa variabile non lo sa   qualsiasi cosa sui valori modificati da   l'altro thread. Per evitare questo   problema, se dichiari una variabile come   volatile, quindi non verrà memorizzato   nella cache locale. Ogni volta che filo   stanno aggiornando i valori, è aggiornato   alla memoria principale. Quindi, altri thread   può accedere al valore aggiornato.

Da JLS §17.4.7 Esecuzioni ben formate

  

Consideriamo solo ben formati   esecuzioni. Un'esecuzione E = < PAPÀ,   po, quindi, W, V, sw, hb > è ben formato   se le seguenti condizioni sono vere:

     
  1. Ogni lettura vede una scrittura sullo stesso   variabile nell'esecuzione. Tutto legge   e scrive di variabili volatili   azioni volatili. Per tutte le letture   A, abbiamo W (r) in A e W (r) .v = r.v.   La variabile r.v è volatile se e   solo se r è una lettura volatile, e il   variabile w.v è volatile se e solo   se w è una scrittura volatile.

  2.   
  3. Accade prima che l'ordine sia parziale   ordine. Happens-before è dato   dalla chiusura transitiva di   si sincronizza con i bordi e il programma   ordine. Deve essere un parziale valido   ordine: riflessivo, transitivo e   antisimmetrica.

  4.   
  5. L'esecuzione obbedisce   consistenza intra-thread. Per ciascuno   thread t, le azioni eseguite da t   in A sono gli stessi che sarebbero   generato da quella discussione in   ordine del programma in isolamento, con ciascuno   scrivi wwriting il valore V (w), dato   che ogni lettura r vede il valore   V (W (r)). I valori visti da ciascuna lettura sono   determinato dal modello di memoria. Il   ordine di programma dato deve riflettere il   ordine del programma in cui le azioni   sarebbe eseguito secondo il   semantica intra-thread di P.

  6.   
  7. L'esecuzione avviene - prima che sia coerente   (§17.4.6).

  8.   
  9. L'esecuzione obbedisce   coerenza dell'ordine di sincronizzazione. Per   tutte le letture volatili r in A, non lo è   il caso che sia così (r, W (r)) o   che esiste una vittoria scritta A tale   che w.v = r.v e così (W (r), w) e   così (w, r).

  10.   

Link utile: Cosa sappiamo veramente della concorrenza non bloccante in Java?

    
25
2012-06-14 21: 30: 32Z
  1. Mi dispiace ma risponde alla mia ultima domanda sul motivo per cui tutti gli altri non-vol vars non sono visibili a B prima che B legga la variabile volatile? Apprezzo davvero la tua spiegazione anche se è chiarissima!
    2011-06-07 01: 33: 27Z
  2. @ denniss Credo che altre sezioni di JCP spieghino che il modello di memoria di Java permette alle variabili non-volatili di essere essenzialmente lette fuori ordine; il runtime è libero di riordinare l'esecuzione delle istruzioni in cui non influisce sul flusso del programma.
    2011-06-07 02: 38: 10Z
  3. @ denniss: Sì, assolutamente. Leggere variabili volatili è come inserire un blocco sincronizzato, scrivere su una variabile volatile è come lasciare il blocco sincronizzato. Quindi tutti i non-vars non sono visibili a B prima che B legga la variabile volatile.
    2011-06-07 04: 11: 05Z
  4. @ 99tm: Vale la pena sottolineare che esistono differenze tra primitive e oggetti, perché volatile riguarda solo il riferimento dell'oggetto e non l'oggetto stesso: quindi non è possibile dichiarare un oggetto come volatile e definitivo del tutto. Tuttavia, dichiarare un oggetto come finale è molto più veloce, poiché il riferimento non cambia mai: quindi è necessario utilizzare gli oggetti finali ovunque sia possibile. Infine, l'uso di oggetti volatili richiede ancora la sincronizzazione e /o variabili volatili da soli - quando lo si modifica, almeno se si desidera scrivere applicazioni coerenti.
    2014-01-27 14: 13: 43Z
  5. + 1. Ho partecipato a un colloquio pochi giorni fa e mi è stato chiesto di volatile e ho detto che i thread non memorizzeranno il valore nella cache ma prenderanno l'ultimo valore dalla memoria principale. Quindi la domanda è arrivata dove nella memoria principale? Non potrei rispondere a questo? Potete per favore farmi sapere dove nella memoria principale gli oggetti volatili o la semplice variabile primitiva di tipo int memorizzata?
    2017-01-21 11: 53: 05Z

Se una variabile non è volatile, il compilatore e la CPU possono riordinare le istruzioni liberamente come ritengono opportuno, al fine di ottimizzare le prestazioni.

Se la variabile è ora dichiarata volatile, il compilatore non tenta più di ottimizzare gli accessi (letture e scritture) a quella variabile. potrebbe tuttavia continuare a ottimizzare l'accesso per altre variabili.

In fase di runtime, quando si accede a una variabile volatile, la JVM genera appropriate istruzioni sulla barriera di memoria per la CPU. La barriera di memoria ha lo stesso scopo: la CPU impedisce anche di riordinare le istruzioni.

Quando una variabile volatile viene scritta su (dal thread A), tutte le scritture su qualsiasi altra variabile vengono completate (o appariranno come prima) e rese visibili ad A prima della scrittura nella variabile volatile; questo è spesso dovuto a un'istruzione di barriera di memoria-scrittura. Allo stesso modo, qualsiasi lettura su altre variabili, sarà completata (o sembrerà che sia) prima del leggi (dalla discussione B); questo è spesso dovuto a un'istruzione barriera di lettura della memoria. Questo ordinamento di istruzioni che viene applicato dalla barriera (s), significherà che tutte le scritture visibili ad A, saranno visibili B. Ciò tuttavia, non significa che qualsiasi riordinamento delle istruzioni non abbia successo (il compilatore potrebbe aver eseguito il riordino per altre istruzioni); significa semplicemente che se qualsiasi scrittura visibile ad A si è verificata, sarebbe visibile a B. In termini più semplici, significa che l'ordine del programma rigoroso non viene mantenuto.

Indicherò questo articolo su Memory Barriers e JVM Concurrency , se vuoi capire come la JVM emette le istruzioni sulla barriera di memoria, con dettagli più precisi.

Domande correlate

  1. Cos'è una fence di memoria?
  2. Quali sono alcuni trucchi che un processore fa per ottimizzare il codice?
6
2017-05-23 11: 54: 39Z
  1. @ Vinnet, non vi sono problemi a leggere la variabile volatile dalla cache L1, è compito dell'hardware sincronizzare le cachedella CPU (aggiorna o svuota le linee della cache interessate). Passare alla RAM mian è terribilmente lento e tali progetti sono destinati a fallire nelle prestazioni.
    2011-06-07 08: 13: 54Z
  2. @ Vinner ha appena controllato l'articolo collegato, è molto buono.
    2011-06-07 08: 23: 15Z
  3. C'è qualche garanzia che un'implementazione Java userà la semantica che assomiglia alle barriere della memoria "complete"? A mio parere, anche se il JIT inserisce un'istruzione di barriera di memoria prima di un negozio di campo finale, ad esempio, ciò non impedirebbe di spostare ciò che le specifiche JVM considererebbero codice "non correlato" attraverso la barriera. Non conosco alcun mezzo con cui il codice Java possa semplicemente dire "Voglio un ricordo qui, e non voglio che nulla si muova su di esso". In .NET un blocco sincronizzato lo raggiungerebbe, ma in Java non lo farà.
    2014-12-03 18: 34: 25Z

I thread sono autorizzati a memorizzare nella cache valori variabili che altri thread potrebbero avere da quando li hanno letti. La parola chiave volatile forza tutti i thread a non memorizzare i valori nella cache.

    
3
2011-06-07 01: 24: 52Z
  1. Una grande spiegazione è semplice.
    2015-12-17 12: 16: 34Z

Questo è semplicemente un bonus aggiuntivo che ti viene fornito dal modello di memoria, se lavori con variabili volatili.

Normalmente (vale a dire in assenza di variabili volatili e sincronizzazione), la VM può rendere variabili da un thread visibili ad altri thread nell'ordine che desidera, o per niente. Per esempio. il thread di lettura potrebbe leggere alcune combinazioni di versioni precedenti di assegnazioni di variabili di altri thread. Ciò è causato dal fatto che i thread possono essere eseguiti su CPU diverse con le proprie cache, che vengono copiate solo in alcuni casi nella "memoria principale" e inoltre mediante il riordino del codice per scopi di ottimizzazione.

Se hai usato una variabile volatile, non appena il thread B ha letto un valore X da esso, la VM si assicura che tutto ciò che il thread A ha scritto prima di scrivere X sia visibile anche a B. (E anche tutto ciò che A ha ottenuto garantito come visibile, transitivamente).

Garanzie simili sono fornite per blocchi sincronizzati e altri tipi di blocchi.

    
1
2011-06-07 01: 26: 00Z
fonte posta Qui