I membri di un ArrayList
non sono protetti da alcuna barriera di memoria, quindi non è garantito che le modifiche siano visibili tra i thread. Questo si applica anche quando l'unico "cambiamento" che viene mai fatto alla lista è la sua costruzione.
Qualsiasi dati condivisi tra thread richiede una "barriera di memoria" per garantirne la visibilità. Ci sono diversi modi per farlo.
In primo luogo, qualsiasi membro dichiarato final
e inizializzato in un costruttore è visibile a qualsiasi thread dopo il completamento del costruttore.
Le modifiche a qualsiasi membro dichiarato volatile
sono visibili a tutti i thread. In effetti, la scrittura viene "svuotata" da qualsiasi cache alla memoria principale, dove può essere vista da qualsiasi thread che accede alla memoria principale.
Ora diventa un po 'più complicato. Qualsiasi scrittura effettuata da un thread prima dello che le scritture di thread su una variabile volatile vengono svuotate. Allo stesso modo, quando un thread legge una variabile volatile, la sua cache viene cancellata e le letture successive possono ripopolarlo dalla memoria principale.
Infine, un blocco synchronized
è come una lettura volatile e in scrittura, con la qualità aggiunta di atomicità. Quando il monitor viene acquisito, la cache di lettura del thread viene cancellata. Quando il monitor viene rilasciato, tutte le scritture vengono scaricate nella memoria principale.
Un modo per fare questo lavoro è di avere il filo che riempie la struttura dei dati condivisi assegnare il risultato a una variabile volatile
(o un AtomicReference
, o altro oggetto adatto java.util.concurrent
). Quando altri thread accedono a tale variabile, non solo sono garantiti per ottenere il valore più recente per quella variabile, ma anche eventuali modifiche apportate alla struttura dati dal thread prima che esso assegni il valore alla variabile.
'Posso garantire che i dati in queste strutture non cambieranno, quindi in questo caso è perfettamente possibile leggere le variabili contemporaneamente senza sincronizzazione. –