Uninitialized object leaked to another thread despite no code explicitly leaking it?(尽管没有代码明确泄漏它,但未初始化的对象泄漏到另一个线程?)
问题描述
让我们看看这个简单的 Java 程序:
Let's see this simple Java program:
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));
}
}
主线程
主线程创建 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:
$ java A
0
为什么轮询线程能够看到 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
这篇关于尽管没有代码明确泄漏它,但未初始化的对象泄漏到另一个线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:尽管没有代码明确泄漏它,但未初始化的对象泄漏到另一个线程?
- 如何使用WebFilter实现授权头检查 2022-01-01
- Eclipse 插件更新错误日志在哪里? 2022-01-01
- C++ 和 Java 进程之间的共享内存 2022-01-01
- Java包名称中单词分隔符的约定是什么? 2022-01-01
- Spring Boot连接到使用仲裁器运行的MongoDB副本集 2022-01-01
- Jersey REST 客户端:发布多部分数据 2022-01-01
- Safepoint+stats 日志,输出 JDK12 中没有 vmop 操作 2022-01-01
- value & 是什么意思?0xff 在 Java 中做什么? 2022-01-01
- 将log4j 1.2配置转换为log4j 2配置 2022-01-01
- 从 finally 块返回时 Java 的奇怪行为 2022-01-01
