Dog*_*Dog 4 java concurrency initialization memory-visibility
让我们看看这个简单的Java程序:
import java.util.*;
class A {
static B b;
static class B {
int x;
B(int x) {
this.x = x;
}
}
public static void main(String[] args) {
new Thread() {
void f(B q) {
int x = q.x;
if (x != 1) {
System.out.println(x);
System.exit(1);
}
}
@Override
public void run() {
while (b == null);
while (true) f(b);
}
}.start();
for (int x = 0;;x++)
b = new B(Math.max(x%2,1));
}
}
Run Code Online (Sandbox Code Playgroud)
主线程
主线程创建的实例B与x设置为1,则该实例写入静态字段A.b.它永远重复这个动作.
投票线程
生成的线程轮询直到它发现A.b.x不是1.
?!?
有一半的时间它按预期进入无限循环,但有一半时间我得到这个输出:
$ java A
0
Run Code Online (Sandbox Code Playgroud)
为什么轮询线程能够看到一个B已经x不设置为1?
x%2而不仅仅是x因为这个问题是可以重现的.
我在linux x64上运行openjdk 6.
Eug*_*ene 10
这就是我的想法:因为b不是最终的,编译器可以自由地重新排序操作,对吧?因此,这基本上是一个重新排序的问题,因此不安全的发布问题将变量标记为final将解决问题.
或多或少,它与Java内存模型文档中提供的示例相同.
真正的问题是这是如何可能的.我也可以在这里推测(因为我不知道编译器将如何重新排序),但是在写入x之前,可能会将对B的引用写入主存储器(其他线程可见).在这两个操作之间,读取发生,因此为零值