Lorsque vous donnez votre liste à un autre thread par des moyens sûrs (par exemple en utilisant un bloc synchronisé, une variable volatile ou un AtomicReference
), il est garanti que le second thread voit la liste entière dans l'état où elle se trouvait lors du transfert (ou tout état ultérieur, mais pas un état antérieur).
Si vous ne le modifiez pas par la suite, vous n'avez pas non plus besoin de votre liste synchronisée.
Edit (après quelques commentaires, pour étayer mes dires) :
Je suppose ce qui suit :
-
nous avons une variable volatile list
.
volatile List<String> list = null;
-
Fil A :
- crée une liste L et remplit L d'éléments.
- fixe
list
pour pointer vers L (ce qui signifie écrit L à list
)
- n'effectue aucune autre modification sur L.
Source de l'échantillon :
public void threadA() {
List<String> L = new ArrayList<String>();
L.add("Hello");
L.add("World");
list = l;
}
-
Fil B :
- lit K à partir de
list
- itère sur K, en imprimant les éléments.
Source de l'échantillon :
public void threadB() {
List<String> K = list;
for(String s : K) {
System.out.println(s);
}
}
-
Tous les autres fils ne touchent pas la liste.
Maintenant, nous avons ceci :
-
Les actions 1-A et 2-A du fil A sont ordonnées par ordre de programme donc 1 vient avant 2.
-
Les actions 1-B et 2-B dans le fil B sont ordonnées par ordre de programme donc 1 vient avant 2.
-
L'action 2-A dans le fil A et l'action 1-B dans le fil sont ordonnées par ordre de synchronisation donc 2-A vient avant 1-B, puisque
Une écriture dans une variable volatile (§8.3.1.4) v se synchronise avec toutes les lectures ultérieures de v par n'importe quel thread (où suivant est défini selon l'ordre de synchronisation).
-
El se passe avant -L'ordre est la fermeture transitive des ordres de programme des threads individuels et de l'ordre de synchronisation. Nous avons donc :
1-A se produit avant 2-A se produit avant 1-B se produit avant 2-B
et donc 1-A se produit avant 2-B.
-
Enfin,
Si une action se produit avant une autre, alors la première est visible et ordonnée avant la seconde.
Ainsi, notre fil itératif peut vraiment voir toute la liste, et pas seulement certaines parties de celle-ci. Ainsi, transmettre la liste avec une seule variable volatile est suffisant, et nous n'avons pas besoin de synchronisation dans ce cas simple.
Une dernière modification (ici, puisque j'ai plus de liberté de formatage que dans les commentaires) concernant l'ordre des programmes du fil A. (J'ai également ajouté un exemple de code ci-dessus).
A partir du JLS (section ordre de programme ) :
Parmi toutes les actions inter-filières effectuées par chaque fil t, l'ordre du programme de t est un ordre total qui reflète l'ordre dans lequel ces actions seraient exécutées selon la sémantique intra-fil de t.
Alors, quels sont les sémantique intra-fil du fil A ?
Quelques paragraphes ci-dessus :
Le modèle de mémoire détermine quelles valeurs peuvent être lues à chaque point du programme. Les actions de chaque thread isolément doivent se comporter de la manière gouvernée par la sémantique de ce thread, à l'exception du fait que les valeurs vues par chaque lecture sont déterminées par le modèle de mémoire. Lorsque nous faisons référence à cela, nous disons que le programme obéit à sémantique intra-fil . La sémantique intra-fil est la sémantique des programmes à un seul fil. programmes monofilaires, et permettent la prédiction complète du comportement d'un fil. un thread basé sur les valeurs vues par les actions de lecture au sein du thread. Pour déterminer si les actions du thread t dans une exécution sont légales, nous évaluons simplement la l'implémentation du thread t telle qu'elle serait exécutée dans un contexte de thread unique, comme défini dans le reste de cette spécification.
Le reste de la présente spécification comprend section 14.2 (Blocs) :
Un bloc est exécuté en exécutant chacune des déclarations de variables locales et les autres instructions dans l'ordre de la première à la dernière (de gauche à droite).
Donc, le ordre de programme est en effet l'ordre dans lequel les déclarations/expressions sont données dans le code source du programme.
Ainsi, dans notre exemple de source, les actions mémoire créer une nouvelle ArrayList , ajouter "Bonjour" , Ajouter "Monde". et affecter à list
(les trois premières consistent en un plus grand nombre de sous-actions) sont en effet en cette commande de programme .
(La VM ne doit pas nécessairement exécuter les actions dans cet ordre, mais ce ordre de programme contribue toujours à la se passe avant ordre, et donc à la visibilité pour les autres fils).