线程难以理解的行为

时间:2018-03-03 08:32:23

标签: java multithreading

我正在阅读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) 同步线程不像第一个变体那样吗?

3 个答案:

答案 0 :(得分:3)

本书解释说,这是因为提升编译器优化,第一个代码可能永远运行。

简而言之,代码:

while (!stop)
    i++;

可能会更改为:

if (!stop)
    while (true)
        i++;

这实际上意味着后台(第二个)线程在第一个示例中继续运行;但优化不适用于第二个代码。仅提出同步作为避免编译器优化的方法之一。 有关此优化的更多信息,请访问this questionthis one

答案 1 :(得分:2)

实际上,正确的解决方案是将变量stop声明为volatile。

答案 2 :(得分:1)

仅仅因为你的程序在测试时停止并不意味着它会被保证停止。您的代码已损坏,但您可能会使用它,部分原因是某些CPU架构(包括x86)具有比Java更强大的内存模型。在Java支持的其他体系结构上,您的程序可能无法停止。这就是线程安全漏洞如此阴险的原因。 测试线程安全非常困难,因此您只需了解规则并遵循它们。