首页 > 解决方案 > Android ART 和 HotSpot 在非易失性变量可见性方面的行为是否不同?

问题描述

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

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

据我所知,java 发生前规则,非易失性在多线程中不可见,就像下面代码在 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();
        }
    }
}

标签: javaandroidhotspothappens-beforenon-volatile

解决方案


非易失性在多线程中不可见,就像下面代码在 Hotspot 上的行为一样。

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

您绝对正确,它是特定于 VM 的,而且它可能/可能甚至是特定于处理器架构的,因为不同的架构可能会为“免费”提供不同数量的同步,或者具有不同数量的缓存会影响是否读取内存地址从核心的缓存或从主内存中获取。

总之,你不应该依赖这种行为在任何特定的虚拟机上以任何特定的方式工作——它可能会在没有警告的情况下发生变化。


推荐阅读