首页 > 解决方案 > 非易失性字段何时写入主存储器

问题描述

因为它done是非易失性的,所以我希望线程 1 将继续执行并打印出“完成”。

但是当我运行程序时,这是控制台的输出

Done
Undo

这意味着线程 2 的更新被线程 1 看到了,对吧?(但done不是一个易变的领域。)

我的解释是线程 1 和线程 2 在同一个内核中运行。这样他们就可以看到提交的更新,如果我错了,请纠正我。

总的来说,我的问题是为什么线程1可以看到线程2的变化?这与 CPU 缓存回写/通过主内存有关吗?如果是,什么时候发生?

public class Done {

    boolean done = true;

    public void m1() throws InterruptedException {
        while (this.done) {
            System.out.println("Done");
        }
        System.out.println("Undo");
    }

    public void undo() {
        done = false;
    }

    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool();
        Done v = new Done();
        es.submit(() -> {
            try {
                v.m1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }); // thread 1

        es.submit(() -> {
            v.undo();
        }); // thread 2

        es.shutdown();
    }
}

标签: javamultithreadingvolatile

解决方案


Java 内存模型的保证仅以一种方式起作用。如果某些事情得到保证,例如 volatile 写入的可见性,那么它将 100% 的工作。

如果没有保证,并不意味着它永远不会发生。有时其他线程会看到非易失性写入。如果您在具有不同 JVM 的不同机器上多次运行此代码,您可能会看到不同的结果。


推荐阅读