【发布时间】:2011-06-23 12:34:24
【问题描述】:
我在高级 Java 线程课程中的老师说了一些我不确定的话。
他表示以下代码不一定会更新ready 变量。据他介绍,两个线程不一定共享静态变量,特别是在每个线程(主线程与ReaderThread)都在自己的处理器上运行并且因此不共享相同的寄存器/缓存/等的情况下一个 CPU 不会更新另一个。
本质上,他说ready可能会在主线程中更新,但不会在ReaderThread中更新,因此ReaderThread会无限循环。
他还声称该程序可以打印0 或42。我了解如何打印42,但不了解0。他提到当number 变量设置为默认值时会出现这种情况。
我想也许不能保证在线程之间更新静态变量,但这让我觉得 Java 很奇怪。使ready volatile 可以解决这个问题吗?
他展示了这段代码:
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready) Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
【问题讨论】:
-
非局部变量的可见性不取决于它们是静态变量、对象字段还是数组元素,它们都有相同的考虑。 (存在数组元素不能变为 volatile 的问题。)
-
问问你的老师他认为什么样的建筑可以看到“0”。然而,理论上他是对的。
-
@bestsss 提出这样的问题会向老师表明他错过了他所说的全部内容。关键是有能力的程序员了解什么是有保证的,什么不是保证的,并且不要依赖没有保证的东西,至少在不准确理解什么是不保证的以及为什么不保证的情况下是这样。
-
它们在同一个类加载器加载的所有东西之间共享。包括线程。
-
你的老师(和公认的答案)是 100% 正确的,但我会提到它很少发生——这种问题会隐藏多年,只有在它会出现时才会出现是最有害的。即使是试图暴露问题的简短测试也倾向于表现得好像一切都很好(可能是因为他们没有时间让 JVM 进行太多优化),所以这是一个非常值得关注的问题。
标签: java multithreading concurrency static memory-visibility