2012-03-26 8 views
7

Dal libro "Java Concurrency in Practice" pagina 26:Come comprendere "La variabile non partecipa agli invarianti con altre variabili di stato quando si utilizza la parola chiave volatile"?

È possibile utilizzare le variabili volatili solo se sono rispettate tutte le seguenti criteri:

  • Scrive alla variabile non dipendono suo valore attuale , oppure si può garantire che solo un singolo thread sempre aggiorna il valore;

  • I variabledi non partecipano agli invarianti con altre variabili di stato; e

  • Il blocco non è richiesto per nessun altro motivo mentre si sta accedendo alla variabile.

Come da comprendere "La variabile non partecipa invarianti con altre variabili di stato quando si utilizza parola chiave volatile"?

+0

Qualche altro contesto sarebbe utile, altrimenti sarei solo indovinando cosa potrebbe significare. –

+0

Spiacente, ho aggiunto il contesto ora –

+0

Nel mio libro è 39 pagina – gstackoverflow

risposta

15

Una semplice definizione di "invariante": una condizione che è sempre vera durante la vita di un oggetto.

Volatile variables do not share the atomicity features of synchronized blocks.

Ecco perché non è possibile utilizzarli in una classe che ha invarianti che riguardano più variabili.

Ad esempio, immagina di avere un class per modellare un intervallo di tempo descritto da due variabili: start e end. Una condizione invariante può essere che start è sempre minore o uguale a end. Se entrambe le variabili (come l'esempio) sono dichiarate volatili, è possibile fare affidamento sulle funzionalità di visibilità di volatile ma non si può essere sicuri che durante una modifica che coinvolge entrambe le variabili, l'invariante sia sempre soddisfatto. Pensate:

public void setInterval(Date newStart, Date newEnd) 
{ 
// Check if inputs are correct 

// Here the object state is valid 
start = newStart; 

// If another thread accesses this object now it will 
// see an invalid state because start could be greater than end 

end = newEnd; 
// Here the object state is valid again 
} 

In questo caso si può essere sicuri che il cambiamento è visibile a tutti i thread, ma nel mezzo delle due istruzioni stato oggetto potrebbe essere non valido. Poiché è possibile accedervi da altri thread (ricordare che si tratta di un caso semplice, quindi è possibile ma non probabile), la condizione invariante "start < end" potrebbe essere interrotta.

Ecco perché l'uso di volatile è in qualche modo scoraggiato al di fuori di un (piccolo) insieme di modelli ben definiti. Una variabile volatili deve essere utilizzato solo se queste condizioni sono soddisfatte:

  • La variabile non è coinvolto in invarianti relativi ad altre variabili (per i motivi esposti in precedenza).
  • Il valore da scrivere sulla variabile non dipende dal suo valore corrente.

Per esempio l'espressione int a = i++; non è atomica allora non è - in senso stretto - thread-safe perché sarà riscritto con qualcosa di simile:

int temp = i; 
i = i + 1; 
int a = temp; 

Per rendere atomica da un punto di vista filo si può immaginare una classe come questa:

public class MyAtomicInteger 
{ 
    public synchronized increment() 
    { 
    x = x + 1; 
    } 

    private int x; 
} 

Certo che esiste una vera e propria ESECUZIONE Questa funzione di AtomicInteger è parte del pacchetto java.util.concurrent.atomic e fornisce alcune semplici routine di base per la programmazione concorrente senza blocchi.

+0

C'è un errore: non è 'i = i + 1' ma' i = temp + 1' nel campione di incremento 'i', altrimenti porta a sottostanti infiniti poiché 'i = i + 1' è uguale all'operazione' i ++ '. – Mik378

+0

@ Mik378 prima dell'incremento "i == temp" quindi "i = i + 1" equivale a "i = temp + 1". È così che "++" non viene espanso "+", quindi "i + 1" non sarà più espanso –

+0

Capito, grazie. – Mik378

Problemi correlati