我正在阅读J. Bloch的Effective Java,在并发章节中有一个例子:
public class Main {
private static boolean stop;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (!stop) {
System.out.println(i);
}
}).start();
TimeUnit.SECONDS.sleep(1);
stop = true;
}
}
此示例显示没有同步子线程将不会停止,因为它无法看到主线程所做的更改。但是如果我们改变代码:
System.out.println
申请将在1秒后停止。那么有人可以解释为什么=26000-sum(D5:D)
同步线程不像第一个变体那样吗?
答案 0 :(得分:3)
本书解释说,这是因为提升编译器优化,第一个代码可能永远运行。
简而言之,代码:
while (!stop)
i++;
可能会更改为:
if (!stop)
while (true)
i++;
这实际上意味着后台(第二个)线程在第一个示例中继续运行;但优化不适用于第二个代码。仅提出同步作为避免编译器优化的方法之一。 有关此优化的更多信息,请访问this question和this one。
答案 1 :(得分:2)
实际上,正确的解决方案是将变量stop声明为volatile。
答案 2 :(得分:1)
仅仅因为你的程序在测试时停止并不意味着它会被保证停止。您的代码已损坏,但您可能会使用它,部分原因是某些CPU架构(包括x86)具有比Java更强大的内存模型。在Java支持的其他体系结构上,您的程序可能无法停止。这就是线程安全漏洞如此阴险的原因。 测试线程安全非常困难,因此您只需了解规则并遵循它们。