Java Android ART和HotSpot在非易失性变量可见性方面表现是否不同;

Java Android ART和HotSpot在非易失性变量可见性方面表现是否不同;,java,android,hotspot,happens-before,non-volatile,Java,Android,Hotspot,Happens Before,Non Volatile,我在HotSpot和Android ART上测试了下面的代码,但结果不同 在热点上,MyThread从不获取更新的isRunning,它获取isRunning=true始终。。。 但是当我在ART上测试它时,MyThread可以得到更新的isRunning并正常退出循环 正如我所知,java在规则之前发生,非易失性在多线程中是不可见的,就像下面代码在Hotspot上的行为一样 这是否取决于虚拟机实现?或者安卓艺术有自己的优化 class MyThread extends Thread {

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


在热点上,
MyThread
从不获取更新的
isRunning
,它获取
isRunning
=true始终。。。 但是当我在ART上测试它时,
MyThread
可以得到更新的
isRunning
并正常退出循环

正如我所知,java在规则之前发生,非易失性在多线程中是不可见的,就像下面代码在Hotspot上的行为一样

这是否取决于虚拟机实现?或者安卓艺术有自己的优化

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

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

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

您肯定是对的,它是特定于VM的,甚至可能是特定于处理器体系结构的,因为不同的体系结构可能会提供不同数量的“免费”同步,或者具有不同数量的缓存,从而影响内存地址是从核心缓存读取还是从主内存获取

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

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

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

您肯定是对的,它是特定于VM的,甚至可能是特定于处理器体系结构的,因为不同的体系结构可能会提供不同数量的“免费”同步,或者具有不同数量的缓存,从而影响内存地址是从核心缓存读取还是从主内存获取


总之,你永远不要依赖这种行为在任何特定的虚拟机上以任何特定的方式工作,它可能会在没有警告的情况下更改。

谢谢你回答这个问题,我想我基本上理解了这个问题。很高兴它能帮到你!如果您认为答案回答了问题,请随意将其标记为已接受,以便其他人更容易找到。感谢您回答此问题,我想我基本上理解此问题。很高兴它有帮助!如果您认为答案回答了问题,请随时将其标记为已接受,以便其他人更容易找到。”
MyThread
从未获得更新的
isRunning
,它获得
isRunning=true
始终…-或者编译器优化了
而(true)
,这没有任何副作用(如调用函数或访问volatile变量)。也就是说,你有条件循环
if(isRunning==false)而(true);
。“
MyThread
从不获取更新的
isRunning
,它获取
isRunning=true
总是…”-或者编译器优化了
while(true)
没有副作用(如调用函数或访问volatile变量)。也就是说,如果(isRunning==false)而(true),则使用条件循环