"Ciao, Amico!"

"Ciao, Eli!"

"Voglio parlarti del modificatore volatile. Sai cos'è?"

"Qualcosa che ha a che fare con i fili. Non ricordo esattamente."

"Allora ascolta. Ecco alcuni dettagli tecnici per te:"

"Un computer ha due tipi di memoria: memoria globale (ordinaria) e memoria integrata nel processore. La memoria integrata del processore è suddivisa in registri, una cache di primo livello (L1), una cache di secondo livello (L2) e terzo livello (L3)."

"Questi tipi di memoria hanno velocità diverse. La memoria più veloce e più piccola sono i registri, quindi la cache del processore (L1, L2, L3) e infine la memoria globale (la più lenta)."

"La memoria globale e la cache del processore funzionano a velocità molto diverse, quindi la macchina Java consente a ciascun thread di memorizzare le variabili utilizzate più di frequente nella memoria del thread locale (nella cache del processore)."

"Questo processo può in qualche modo essere controllato?"

"Non proprio. Tutto il lavoro viene svolto dalla macchina Java. È molto intelligente quando si tratta di ottimizzare le prestazioni."

"Ma ecco perché ti sto dicendo questo. C'è un piccolo problema. Quando due thread stanno lavorando con la stessa variabile, ognuno può memorizzare una copia nella propria cache locale. E quindi un thread potrebbe cambiare la variabile, ma il secondo potrebbe non vedere il cambiamento, perché sta ancora lavorando con la propria copia della variabile."

"Bene, cosa si può fare allora?"

"I creatori di Java hanno fornito una parola chiave speciale per questa situazione: volatile. Se si accede a una variabile da thread diversi, è necessario contrassegnarla con il modificatore volatile, in modo che la macchina Java non la inserisca nella cache. Di solito è così sembra:"

public volatile int count = 0;

"Oh, mi ricordo. Ne hai già parlato. Lo so già."

"Certo che lo sai. Ma te ne sei ricordato solo quando te l'ho detto."

"Ehm, beh, ho dimenticato un po'."

"La ripetizione è la madre dell'apprendimento!"

"Ecco alcuni nuovi fatti sul modificatore volatile. Il modificatore volatile garantisce solo che la variabile verrà letta e scritta in modo sicuro. Non garantisce che verrà modificata in modo sicuro."

"Qual è la differenza?"

"Guarda come viene modificata la variabile:"

Codice Cosa succede realmente: Descrizione
count++
register = count;

register = register+1;

count = register;
Passaggio 1.
Il valore della variabile count viene copiato dalla memoria globale a un registro del processore.

Passaggio 2.
All'interno del processore, la variabile di registro viene incrementata di 1.

Passaggio 3.
Il valore della variabile viene copiato dal processore alla memoria globale.

"Wow! Quindi, tutte le variabili vengono modificate solo nel processore?"

"Sì."

"E i valori vengono copiati avanti e indietro: dalla memoria al processore e viceversa?"

"Sì."

"Il modificatore volatile garantisce che quando si accede alla variabile count verrà letta dalla memoria (passaggio 1). E se un thread desidera assegnare un nuovo valore, sarà sicuramente nella memoria globale (passaggio 3)."

"Ma la macchina Java non garantisce che non ci sarà alcun cambio di thread tra i passaggi 1 e 3."

"Quindi, incrementare la variabile di 1 è in realtà tre operazioni?"

"SÌ."

"E se due thread vogliono eseguire contemporaneamente count++, potrebbero interferire l'uno con l'altro?"

"Sì, dai un'occhiata:"

Discussione 1 Filo 2 Risultato
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

"Quindi, puoi accedere alla variabile, ma cambiarla è ancora rischioso?"

"Beh, puoi cambiarlo, ma stai attento ☺"

"Come?"

" sincronizzato  è il nostro migliore amico."

"Vedo."