非易失性字段什么时候写入主存

When is non-volatile field write to main memory

因为 done 是非易失性的,所以我预计线程 1 将继续执行并打印出 "Done"。

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

Done
Undo

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

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

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

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();
    }
}

Java memory model 的保证仅以一种方式起作用。如果某些东西是有保证的,比如易失性写入的可见性,那么它将在 100% 的时间内工作。

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