gpt4 book ai didi

java - 为什么使用 "volatile"在这里没有显示任何差异?

转载 作者:行者123 更新时间:2023-12-01 18:35:22 25 4
gpt4 key购买 nike

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

   static volatile boolean shutdownRequested = false;

...

public void shutdown() { shutdownRequested = true; }

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

我在我的机器上尝试使用和不使用“ volatile ”,但它们没有显示任何区别:它们都可以关闭。那么出了什么问题呢?我的代码有什么问题吗,还是取决于Java编译器的版本?

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

最佳答案

我假设你的意思是你有这样的设置:

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

您发现,即使没有 volatile ,关闭也能正常工作。

通常情况下这是正确的:最终可能会看到非 volatile 写入。重要的是,无法保证一定会出现这种情况,并且您不能依赖它。在实际使用中你可能还会发现,在没有 volatile 的情况下,有一个小但明显的延迟。

Volatile 提供保证,写入内容立即被看到。

这里有一些代码可以重现我们在评论中讨论的 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 字节码,对其进行优化,并将其编译为 native 程序集。 HotSpot 是 Java 如此快速的原因之一。根据我的经验,HotSpot 重新编译的代码可以轻松提高 10 倍。 HotSpot 在优化方面也比常规 Java 编译器(例如 javac 或 IDE 供应商制作的其他编译器)更加积极。

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

从Java内存模型的角度来看,只要绝对没有内存同步HotSpot就允许这样做,这是有道理的。 HotSpot 知道没有理由需要查看更新,因此不会费心检查。

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

所以,这再次表明您不能依赖非 volatile 读取。

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

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com