读Java语言规范,我发现这个摘录有关最终字段:如果您将对象分配给最终字段,其他线程是否会看到该对象的非最终/非易失性字段的先前更新?
最终场的使用模式很简单:将最终场 在该对象的构造方法的对象;并且不要在对象的构造函数完成之前,在线程可以看到它的地方写入 引用。如果遵循这个 ,那么当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本。 它还会看到任何对象或 数组引用的版本,这些最终字段至少为最新的 ,因为最终字段为。
链接:https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5
我的问题是,做 “版本” 意味着更新?这意味着在构造之后,最终字段引用的对象的非最终/非易失性字段也将从主内存(不是本地缓存)中读取?
例
所以我们说thread #1
创建objectB
并设置其非final /非易失性的领域之一。
然后thread #2
集,同一领域不同的东西,造成其他一些objectA
设定为objectB
最后的字段,然后把那objectA
的地方在那里thread #1
可以得到它。
thread #1
然后获得objectA
,并将其最终字段视为objectB
。 thread #1
有没有可能看不到由thread #2
所做的更改为objectB
?
或者在这里表示我的意思了一些代码:
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;
}
}
}
代码似乎读取更新的价值,但我不知道这是刚走出随机运气。
很适合第一个问题。 – lexicore