Uninitialized object leaked to another thread despite no code explicitly leaking it?(尽管没有代码明确泄漏它,但未初始化的对象泄漏到另一个线程?)
问题描述
让我们看看这个简单的 Java 程序:
Let's see this simple Java program:
主线程
主线程创建 B
的实例,并将 x
设置为 1,然后将该实例写入静态字段 A.b
.它会永远重复这个动作.
The main thread creates an instance of B
with x
set to 1, then writes that instance to the static field A.b
. It repeats this action forever.
轮询线程
生成的线程会轮询,直到发现 A.b.x
不是 1.
The spawned thread polls until it finds that A.b.x
is not 1.
?!?
一半的时间按预期进入无限循环,但一半的时间我得到这个输出:
Half the time it goes in an infinite loop as expected, but half the time I get this output:
为什么轮询线程能够看到 x
未设置为 1 的 B
?
Why is the polling thread able to see a B
that has x
not set to 1?
x%2
而不仅仅是 x
在这里仅仅是因为问题可以重现.
x%2
instead of just x
is here simply because the issue is reproducible with it.
我在 linux x64 上运行 openjdk 6.
I'm running openjdk 6 on linux x64.
推荐答案
这是我的想法:因为 b 不是 final,编译器可以随意重新排序操作,对吧?所以这从根本上说是一个重新排序问题,结果是 不安全的发布问题将变量标记为 final 将解决问题.
Here is what I think: because b is not final, the compiler is free to reorder the operations as it likes, right? So this, fundamentally is a reordering issue and as a result a unsafe publication issue Marking the variable as final will fix the problem.
或多或少,它与 Java 内存模型文档.
真正的问题是这怎么可能.我也可以在这里推测(因为我不知道编译器将如何重新排序),但可能在写入 x 之前,对 B 的引用被写入主内存(另一个线程可见).在这两个操作之间发生读取,因此零值
The real question is how is this possible. I can also speculate here (since I have no idea how the compiler will reorder), but maybe the reference to B is written to the main memory (where it is visible to the other thread) BEFORE the write to x happens. In between these two operations the read happens, thus the zero value
这篇关于尽管没有代码明确泄漏它,但未初始化的对象泄漏到另一个线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!