我正在学习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/