【问题标题】:When is non-volatile field write to main memory非易失性字段何时写入主存
【发布时间】:2019-08-14 20:55:36
【问题描述】:

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

【问题讨论】:

  • 不保证可见性,但仍有可能。这就是非同步程序的问题:它们的输出是不可预测的。没有正确同步的程序几乎没有什么有用的结果。
  • My explanation is that thread 1 and thread 2 are running in the same core. 您可能正在英特尔硬件上运行。英特尔的缓存是连贯的,这意味着更新甚至对其他内核也是可见的。因此,英特尔硬件提供了比 Java 更强大的可见性保证。为什么?我认为这是因为 Java 被设计为可移植的,它的设计者希望选择在不完全缓存一致的硬件上运行。

标签: java multithreading volatile


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 2018-01-18
    • 1970-01-01
    • 1970-01-01
    • 2019-09-28
    • 2020-07-28
    • 2015-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多