2

正如预期的那样,下面程序中的读取器线程将永远运行,因为它将停止标志(非易失性)缓存在其本地处理器的缓存中。然而,一旦我在阅读器线程上取消注释 println,标志就会得到更新的标志值并且程序停止。这是怎么可能的,因为编写器线程只将标志写入其自己的本地缓存并且尚未刷新到主内存?

注意:在 MacBook Pro x86 架构的机器上运行这个程序。

public class FieldVisibility {
    boolean stop = false;
    public static void main(String[] args) throws Exception {
        FieldVisibility fv = new FieldVisibility();

        Runnable writerThreadJob = () -> {  fv.writer();    };
        Runnable readerThreadJob = () -> {  fv.reader();    };

        Thread writerThread = new Thread(writerThreadJob);
        Thread readerThread = new Thread(readerThreadJob);

        readerThread.start();
        try {   Thread.sleep(2);    } catch (InterruptedException e) {}
        writerThread.start();
    }

    private void writer() {
        stop = true;
    }

    private void reader() {
        while (!stop) {
//          System.out.println("stop is still false...");
        }
    }
}
4

1 回答 1

1

Margaret Bloom 和 Peter Cordes 已经在评论部分给出了答案。

允许 JIT 将变量提升stop出循环,因为它不是易失性的。这种优化称为循环不变代码运动。

所以下面的循环:

private stop;

private void reader() {
    while (!stop) {
         System.out.println("stop is still false...");
    }
}

可以转化为:

private stop;

private void reader() {
    if(stop) return;

    while (true) {
         System.out.println("stop is still false...");
    }
}

现在很明显,循环永远不会结束。

于 2020-05-18T13:45:42.833 回答