我正在学习Java中volatile的用法。这是我从许多文章中读取的示例代码:

   static volatile boolean shutdownRequested = false;

...

public void shutdown() { shutdownRequested = true; }

public void doWork() {
    while (!shutdownRequested) {
        // do stuff
    }
}


我在带有和不带有“ volatile”的计算机上尝试了此操作,但是它们没有区别:它们都可以关闭。
那怎么了我的代码有什么问题吗,还是取决于Java编译器的版本?

另外:在许多文章中,他们说没有“ volatile”的程序无法成功关闭,因为如果循环内变量while (!shutdownRequested)的值未更改,则Java编译器会将循环while(true)优化为shutdownRequested。但是我的实验结果并不代表这一点。

最佳答案

我认为您的意思是您进行了如下设置:

final Worker theWorker = new Worker(); // the object you show code for

new Thread(new Runnable() {
    public void run() {
        theWorker.doWork();
    }
}.start();

try {
    Thread.sleep(1000L);
} catch(InterruptedException ie) {}

theWorker.shutdown();


您发现的是,即使没有挥发,关机也能正常工作。

通常情况是这样的:最终可能会看到非易失性写入。重要的是,不能保证确实如此,您不能依靠它。在实际使用中,您可能还会发现延迟很小但没有波动。

易失性提供了立即查看写入的保证。

这是一些代码,可能会重现我们在注释中讨论的HotSpot优化:

public class HotSpotTest {
    static long count;
    static boolean shouldContinue = true;

    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            public void run() {
                while(shouldContinue) {
                    count++;
                }
            }
        });
        t.start();

        do {
            try {
                Thread.sleep(1000L);
            } catch(InterruptedException ie) {}
        } while(count < 999999L);

        shouldContinue = false;
        System.out.println(
            "stopping at " + count + " iterations"
        );

        try {
            t.join();
        } catch(InterruptedException ie) {}
    }
}


如果您不知道什么是HotSpot,请快速阅读以下内容:HotSpot是Java just-in-time compiler。在某些代码片段运行了特定的次数(从内存,台式机JVM为1000,服务器JVM为3000)之后,HotSpot提取Java字节码,对其进行优化并将其编译为本机程序集。 HotSpot是Java如此迅捷的原因之一。以我的经验,HotSpot重新编译的代码可以轻松地快十倍。与常规Java编译器(例如javac或IDE供应商制造的其他编译器)相比,HotSpot在优化方面也更具攻击性。

所以我发现,如果让循环先运行足够长的时间,join就会永远挂起。请注意,count在设计上不是易失的。使count易失似乎阻碍了优化。

从Java内存模型的角度来看,只要绝对不存在允许内存同步的HotSpot,就可以理解。 HotSpot知道没有理由需要查看更新,因此它不会打扰检查。

我没有打印HotSpot程序集,因为这需要一些我尚未安装的JDK软件,但是我确定如果这样做,您会发现所提供的链接也有相同的含义。 HotSpot确实确实似乎将while(shouldContinue)优化为while(true)。使用-Xint选项运行程序以关闭HotSpot也会导致看到更新,这也将HotSpot视为罪魁祸首。

因此,它再次表明您不能依赖于非易失性读取。

关于java - 为什么使用“volatile”在这里没有任何区别?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22241566/

10-11 17:16