Volatile variabile in Java

Così sto leggendo questo libro intitolato Java Concurrency in Pratica e mi sono bloccato su questo una spiegazione che mi sembra di non riuscire a comprendere senza un esempio. Questo è il preventivo:

Quando il thread A scrive un volatile
variabile e successivamente thread B
si legge che la stessa variabile, i valori
di tutte le variabili che sono visibili all’
A prima della scrittura volatile
variabile diventare visibile a B dopo
la lettura del volatile variabile.

Qualcuno può dare un controesempio perché “i valori di TUTTE le variabili che erano visibili a A prima della scrittura volatile variabile diventare visibile a B DOPO la lettura del volatile variabile”?

Mi sono confuso perché tutti gli altri non-volatile variabili non diventano visibili a B prima di leggere il volatile variabile?

  • Java Concurrency, in Pratica, è un libro bellissimo. Ogni programmatore java dovrebbe leggere!
  • per dirla semplicemente: la semantica di volatili sono garanzie di ordinazione, in modo che se succede qualcosa prima che l’operazione di volatili (lettura/scrittura) sarebbe come leggere/scrivere prima di ogni operazione, in modo efficace, seguendo lo stesso ordine delle operazioni. Altri compilatori E Cpu sono autorizzati a eseguire out-ordine di lettura/scrittura ed esecuzione per incrementare significativamente le prestazioni.
  • Hanno un aspetto di esempio e spiegazione qui: stackoverflow.com/questions/10620680/…
InformationsquelleAutor denniss | 2011-06-07



5 Replies
  1. 15

    Thread B può avere un CPU-cache locale di quelle variabili. Una lettura di un volatile variabile assicura che tutte le cache intermedie di colore da una precedente scrittura per il volatile è osservato.

    Per esempio, leggere il seguente link, che si conclude con Fissaggio a Doppio controllo di Blocco Volatile”:

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

    • quindi stai dicendo che quando un thread si legge in una variabile VOLATILE, svuota la cache per tutte le altre variabili?
    • Corretto. Java definisce volatile in modo tale che un volatile-lettura di una variabile ha lo stesso effetto memoria come una sincronizzato-iniziare, e un volatile-scrittura di una stessa variabile ha lo stesso effetto memoria come una sincronizzato-end. In altre parole “se volatili (lettura) { do-lavoro; volatili-write }” è come un blocco sincronizzato che permette a più thread di esecuzione non-lavoro, allo stesso tempo.
    • volatile legge non svuotare la cache… (che hanno letto w/o riordino)
    • no, non svuotare la cache, la cache di flussaggio è eseguita da la coerenza della cache di protocollo e livello di hardware. In generale qualsiasi scrittura di una linea di cache tenuto dal processore sarà aggiornato (di solito non scaricato) da eventuali scrivere la stessa linea di cache di un altro processore. Modello di memoria Java non rispetta hardware modello di memoria, appunto, la maggior parte dei modelli sono più deboli. (alcuni link infoq.com/presentations/click-crash-course-modern-hardware con un ottimo video su java e hardware)
    • perché, allora B può solo vedere le altre camere NON-VOL variabili dopo aver letto il VOL var?
    • dopo la scrittura di volatili variabile thread A problemi di memoria recinto, e dunque tutto quello scritto essere svuotati. Dato che B si legge in qualche modo invertire l’ordine prima volatile, poi il resto, sono coerenti. W/o le regole di ordinamento, entrambi i thread sono ammessi per ogni ordine di lettura/scrittura. Questo è ciò che fondamentalmente accade a livello hardware (non si discostano di più da java spec), ma l’affermazione che la cache non vengono svuotati doesesn non rispecchiano la realtà. Una roba del genere causerebbe come 100 volte le prestazioni degradano.
    • href=”http://g.oswego.edu/dl/jmm/cookbook.html” >g.oswego.edu/dl/jmm/cookbook.html Guardare le “Barriere di Memoria” sezione. Nella tabella, un LoadLoad barriera deve essere emessa tra [1 ° operazione = Volatile Carico] e [2 ° operazione = Carico Normale]. (Anche nota dalla tabella in “Multiprocessore” sezione LoadLoad negozi sono no-op su più di una Cpu.) Forse ho impropriamente usato il termine “cache”, ma l’utilizzo di una speculativo di carico durante OOO esecuzione in modo efficace utilizzando un valore memorizzato nella cache, e penso che sia abbastanza per pensare in termini di “cache” in fase di apprendimento circa il JMM.
    • ma LoadLoad non flush cache di per sé (in realtà non penso che si svuota mai). Sul BRACCIO e IA-64 è un ordine di carico (che ho cercato di dire). Reale cache vampate come (CLFLUSH) non sono utilizzati ovunque per le mie conoscenze. L’idea di base non è la cache è oggetto di dumping (e registri non utilizzati), ma che l’operazione di caricamento è ordinato rispetto al precedente volatile carico.
    • altri cerco di sottolineare è: volatile legge sono a buon mercato (può essere a buon mercato come 1-3CPU cicli) e la gente non deve avere paura di usare volatili b/c è costoso. L’effetto collaterale di impedire che alcuni di ottimizzazione detiene ancora vero, ma è in nessun posto vicino l’immissione di un blocco o di L1 cache flush.
    • Ah, vedo il tuo punto. Ho aggiornato la risposta a sottolineare che il volatile-scrivere sta svuotando la cache, e il volatile-si legge semplicemente assicura la coerenza. Che senso ha?

  2. 25

    Dichiarazione di un volatile Java variabile:

    • Il valore di questa variabile non potrà mai essere memorizzati nella cache di thread a livello locale: tutte le letture e le scritture di andare direttamente alla “memoria principale”.
    • Accesso alla variabile comporta come se non ci è racchiuso in un blocco sincronizzato, sincronizzati su se stessa.

    Appena per il vostro riferimento, Quando è volatile necessario ?

    Quando più thread utilizzando la stessa
    variabile, ogni thread avrà la sua
    propria copia di cache locale per
    variabile. Così, quando si tratta di aggiornare il
    valore, è aggiornato in
    cache locale non la principale variabile
    memoria. L’altro thread che è
    utilizzando la stessa variabile non sa
    nulla circa i valori modificati da
    l’altro thread. Per evitare questo
    problema, se si dichiara una variabile come
    volatile, quindi non verrà memorizzata
    nella cache locale. Ogni volta che il thread
    sono l’aggiornamento dei valori, è aggiornato
    alla memoria principale. Così, altri thread
    possono accedere al valore aggiornato.

    Da JLS §17.4.7 Ben Formato Esecuzioni

    Prendiamo in considerazione solo ben formato
    esecuzioni. Un’esecuzione E = < P, A,
    po, così, W, V, sw, hb > è ben formata
    se le seguenti condizioni sono true:

    1. Ogni lettura vede una scrittura stessa
      variabile in esecuzione. Tutte le letture
      e scrive di variabili volatili sono
      volatile azioni. Tutte le letture r in
      Una, abbiamo W(r) e W(r).v = r.v.
      La variabile r.v è volatile e se
      solo se r è una lettura volatile, e il
      variabile w.v è volatile se e solo
      se w è una scrittura volatile.

    2. Accade prima di un ordine parziale
      ordine. Happens-before ordine è dato
      la chiusura transitiva di
      sincronizza-con bordi e programma
      ordine. Deve essere un valido parziale
      ordine: riflessiva, transitiva e
      antisymmetric.

    3. L’esecuzione obbedisce
      intra-filo di coerenza. Per ogni
      filettatura t, le azioni eseguite da t
      in Una sono le stesse come sarebbe
      generato da un filo rosso
      programma-ordine in isolamento, con ogni
      scrivi wwriting il valore V(w), dato
      che ogni lettura r vede il valore
      V(W(r)). Valori da leggere sono
      determinato dal modello di memoria. Il
      programma di ordine, deve riflettere il
      programma ordine in cui le azioni
      vorresti essere eseguiti secondo le
      intra-thread semantica di P.

    4. L’esecuzione è happens-before coerente
      (§17.4.6).

    5. L’esecuzione obbedisce
      sincronizzazione coerenza dell’ordine. Per
      tutti i volatili legge r in a, non è
      il caso che sia così(r, W(r)) o
      che esiste una scrittura vincere Un tale
      che w.v = r.v e così(W(r), w) e
      così(w, r).

    Link Utili : Che cosa sappiamo davvero di non bloccare la concorrenza in Java?

    • Mi dispiace, ma questo non risponde alla mia ultima domanda, perché tutti gli altri non-vol vars non sono visibili a B prima B legge il volatile variabile? Apprezzo davvero la tua spiegazione anche se è chiaro come il cristallo!
    • Credo che altre sezioni del JCP spiega che Java del Modello di Memoria permette di non-volatile variabili per essere essenzialmente leggi di ordine; il runtime è libero di ri-ordinare l’esecuzione di istruzioni in cui non influenzare il flusso del programma.
    • Sì, assolutamente. La lettura di volatili variabile è come entrare in un blocco sincronizzato, la scrittura di un volatile variabile, è come lasciare il blocco sincronizzato. Quindi tutti i non-vars non sono visibili a B prima B legge volatile variabile.
    • 99tm: vale la pena di sottolineare che ci sono differenze tra tipi primitivi e oggetti, perché volatile è solo il riferimento dell’oggetto e non l’oggetto stesso: Pertanto non è possibile dichiarare un oggetto come volatili e finale del tutto. Tuttavia, la dichiarazione di un oggetto come finale è molto più veloce, infatti, dal momento che il riferimento non cambia mai: Quindi è necessario utilizzare oggetti finali, ovunque si può. Infine, l’uso di oggetti volatili ancora bisogno di sincronizzazione e/o variabili volatili da soli quando si cambia, almeno se si vuole scrivere coerenti applicazioni.
    • +1. Ho partecipato a un’intervista di alcuni giorni fa mi è stato chiesto circa volatili e mi ha detto che il thread non nasconderà il valore, ma trovera ‘ l’ultimo valore dalla memoria principale. Quindi la questione è venuto, dove nella memoria principale? Non ho potuto rispondere a questa? Potete per favore fatemi sapere dove nella memoria principale Oggetti volatili o semplici primitive variabile di tipo int memorizzati?
  3. 6

    Se una variabile non è volatile, quindi il compilatore e la CPU, può ri-istruzioni per la libertà che si vede in forma, al fine di ottimizzare le prestazioni.

    Se la variabile è dichiarata volatile, quindi il compilatore non tenta di ottimizzare accessi (lettura e scrittura) a quella variabile. Si può tuttavia continuare a ottimizzare l’accesso ad altre variabili.

    In fase di runtime, quando un volatile si accede variabile, la JVM genera adeguata barriera di memoria istruzioni per la CPU. La barriera di memoria serve allo stesso scopo – la CPU è anche prevenire la re-istruzioni per l’ordinazione.

    Quando un volatile variabile è scritto (da thread A), tutte le scritture di qualsiasi altra variabile sono completati (o almeno sembrano) e visibili per Una prima di scrivere il volatile variabile; questo è spesso causa di una memoria-scrittura barriera di istruzione. Allo stesso modo, qualsiasi legge su altre variabili, sarà completato (o sembra essere) prima della
    leggere (dal thread B); questo è spesso causa di una memoria di lettura barriera di istruzione. Questo ordine delle istruzioni che viene applicato dalla barriera(s), significa che tutte le scritture visibile a Un, sarà visibile B. tuttavia, Questo non significa che qualsiasi nuovo ordine delle istruzioni non successo (il compilatore potrebbe aver eseguito ordini per altre istruzioni); significa semplicemente che se uno scrive visibile di avere verificato, sarebbe visibile a B. In termini più semplici, significa che il rigoroso programma di ordine non viene mantenuta.

    Io punto a questo interessante resoconto su Le Barriere di memoria e con la JVM di Concorrenza, se si vuole capire come la JVM problemi di memoria barriera di istruzioni, in modo più dettagliato.

    Relative domande

    1. Che cosa è una recinzione?
    2. Quali sono alcuni trucchi che un processore di ottimizzare il codice?
    • non c’è nessun problema a leggere volatile variabile da L1 cache, è un compito di hardware per la sincronizzazione della cache della CPU (aggiornamento o flush interessato linee di cache). Andando a mian RAM è terribilmente lento e tali progetti sono destinati a fallire in termini di prestazioni.
    • appena controllato l’articolo linkato, è molto buono.
    • C’è alcuna garanzia che una implementazione Java di usare la semantica simile a “full” barriere di memoria? Dalla mia comprensione, anche se il JIT inserisce una barriera di memoria di istruzioni prima di una finale-campo di memorizzazione, ad esempio, che non impediscono lo spostamento di ciò che la JVM spec avrebbe considerato “estraneo” il codice attraverso la barriera. So che non significa che il codice Java può semplicemente dire “voglio una memoria qui, e io non voglio niente spostato su di esso”. In .NETTO un blocco sincronizzato vorresti raggiungere, ma in Java non.
  4. 3

    I thread possono cache i valori delle variabili che altro thread hanno dato aggiornato dal momento che li leggono. Il volatile parola chiave forze di tutti i thread non i valori di cache.

    • Grande spiegazione è semplice termini.
  5. 1

    Questo è semplicemente un bonus aggiuntivo, il modello di memoria ti dà, se si lavora con variabili volatili.

    Normalmente (cioè in assenza di variabili volatili e di sincronizzazione), la VM può fare variabili da un filo visibile per gli altri thread in qualsiasi ordine si voglia, o non a tutti. E. g. il thread di lettura potrebbe leggere qualche miscela di versioni precedenti di un altro thread assegnazioni di variabili. Questo è causato dal thread forse a funzionare su diverse Cpu con una propria cache, che sono solo a volte copiato la “memoria principale”, e inoltre dal codice di riordino per le finalità di ottimizzazione.

    Se è stato utilizzato un volatile variabile, appena il thread B leggere qualche valore di X, la VM fa in modo che tutto ciò che thread ha scritto prima di scritto X è visibile anche B. (E anche tutto quello che Uno ha garantito, in quanto visibile, in modo transitivo).

    Analoghe garanzie sono date per sincronizzati blocchi e altri tipi di blocchi.

Lascia un commento