La lecture des spécifications du langage Java, je trouve cet extrait sur les champs finaux:Si vous affectez un objet à un champ final, les autres threads verront-ils les mises à jour précédentes des champs non-final/non-volatile de cet objet?
Le modèle d'utilisation des champs final est simple: Définissez les champs final pour un objet dans le constructeur de cet objet; et n'écrivez pas une référence à l'objet en cours de construction à un endroit où un autre thread peut le voir avant que le constructeur de l'objet ne soit terminé. Si ce est suivi, alors lorsque l'objet est vu par un autre thread, ce thread verra toujours la version correctement construite des champs finaux de l'objet . Il verra également les versions de n'importe quel objet ou tableau référencé par ces derniers champs qui sont au moins aussi à jour que que les champs finaux sont.
Lien: https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5
Ma question est de savoir si "versions" mises à jour moyennes? Cela signifie que les champs non-final/non-volatile d'un objet référencé par un champ final seront également lus à partir de la mémoire principale (pas le cache local) après la construction?
Exemple
Alors disons que thread #1
crée un objectB
et définit un de ses non-finales/champs non volatiles.
Ensuite thread #2
ensembles même champ à quelque chose de différent, crée une autre objectA
avec un dernier champ défini comme objectB
, et met ensuite cette objectA
quelque part où thread #1
peut l'obtenir.
thread #1
puis obtient le objectA
et voit son champ final comme objectB
. Est-il possible pour thread #1
de ne pas voir les changements à objectB
faite par thread #2
?
Ou voici un code montrant ce que je veux dire:
public class Test {
private static final ConcurrentLinkedQueue<A> myAs = new ConcurrentLinkedQueue<>();
private static long timer = System.nanoTime() + 3000000000L; // 3 seconds into the future
public static void main(String... args) {
B myB = new B("thread #1"); // Set in thread 1
new Thread(() -> {
myB.setString("thread #2"); // Set in thread 2
myAs.add(new A(myB));
}).start();
for(long i = 0; i < x; i = System.nanoTime()) {} // Busy-wait for about 3 seconds
System.out.println(myAs.poll().getB().getString()); // Print out value
}
public static class A {
private final B b;
public A(B b) {
this.b = b;
}
public B getB() {
return b;
}
}
public static class B {
private String s = null;
public B(String s) {
this.s = s;
}
public String getString() {
return s;
}
public void setString(String s) {
this.s = s;
}
}
}
Le code semble lire les valeurs mises à jour, mais je ne suis pas sûr que ce soit juste pas de chance au hasard.
Assez bien pour la première question. – lexicore