7 java concurrency multithreading volatile thread-safety
阅读Java语言规范,我发现了关于最终字段的摘录:
最终字段的使用模型很简单:在该对象的构造函数中设置对象的最终字段; 并且在对象的构造函数完成之前,不要在另一个线程可以看到的地方写入对正在构造的对象的引用.如果遵循此原因,那么当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本.它还将看到那些最终字段引用的任何对象或数组的版本,这些字段至少与最终字段一样是最新的.
链接:https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5
我的问题是,"版本"是否意味着更新?这意味着最终字段引用的对象的非final/non-volatile字段也将在构造后从主内存(而不是本地缓存)中读取?
例
因此,假设thread #1
创建一个objectB
并设置其非最终/非易失性字段之一.
然后thread #2
将相同的字段设置为不同的字段,创建其他objectA
字段设置为最终字段objectB
,然后将其objectA
放在thread #1
可以获取它的位置.
thread #1
然后得到objectA
,并看到它的最后一个领域objectB
.是否有可能thread #1
看不到objectB
所做的更改thread #2
?
或者这里有一些显示我的意思的代码:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
代码似乎读取了更新的值,但我不确定这是否仅仅是出于随机运气.
小智 0
恕我直言,你总是会看到更新的值。这里发生了两件事
由于我们有冻结操作,其他线程应该能够看到 myB 的内容
更多详细信息: https://shipilev.net/blog/2014/jmm-pragmatics/#_part_v_finals
https://www.ibm.com/developerworks/library/j-jtp03304/index.html