Android ART 和 HotSpot 在非易失性变量可见性方面的行为是否不同?

Do Android ART and HotSpot behave differently in non-volatile variable visibility?

我在 HotSpot 和 Android ART 上测试了以下代码,但结果不同。

在 HotSpot 上,MyThread 永远不会得到更新的 isRunning,它总是得到 isRunning = true... 但是当我在 ART 上测试时,MyThread 可以获取更新后的 isRunning 并正常退出循环...

据我所知 java happens-before 规则,非易失性在多线程中不可见,就像下面代码在 Hotspot 上的行为一样。

是否取决于 VM 实现?或者 Android ART 有自己的优化?

class MyThread extends Thread {
    public boolean isRunning = true;

    @Override
    public void run() {
        System.out.println("MyThread running");
        while (true) {
            if (isRunning == false) break;
        }
        System.out.println("MyThread exit");
    }
}

public class RunThread{
    public static void main(String[] args) {
        new RunThread().runMain();
    }

    public void runMain() {
        MyThread thread = new MyThread();
        try {
            thread.start();
            Thread.sleep(500);
            thread.isRunning = false;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

an non-volatile is not visible across multi-thread, just like the behave of the code below on Hotspot.

不对。非易失性写入,没有任何额外的同步或其他先发生关系,保证对另一个线程中同一变量的读取可见。不过,允许 可见。尽管没有 happens-before 关系,但我绝对看到 HotSpot 使写入跨线程可见。根据我的经验,我怀疑如果你在你的代码中删除 Thread.sleep 调用,HotSpot 也会使对 isRunning 的写入对线程可见,尽管没有任何发生之前的关系在写入和读取之间。

你说得对,它是特定于 VM 的,而且它是 possibly/likely 甚至是特定于处理器架构的,因为不同的架构可能会为 "free" 提供不同的同步量,或者具有不同的同步量影响内存地址是从核心缓存中读取还是从主内存中获取的缓存。

总而言之,您永远不应该依赖这种行为在任何特定 VM 上以任何特定方式工作——它很可能会在没有警告的情况下发生变化。