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.
Qualche altro contesto sarebbe utile, altrimenti sarei solo indovinando cosa potrebbe significare. –
Spiacente, ho aggiunto il contesto ora –
Nel mio libro è 39 pagina – gstackoverflow