gpt4 book ai didi

java - x86 上的 volatile 怎么会丢失更新?

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:00:27 26 4
gpt4 key购买 nike

我尝试使用“count”作为 volatile 来运行以下代码:

ExecutorService e = Executors.newFixedThreadPool(2);
for (int i=0; i<2; i++)
{
e.execute(new Runnable(){
public void run() {
for (int i=0; i<1000000; i++)
count++;
}
}
);
}
e.shutdown();
e.awaitTermination(1, TimeUnit.DAYS);
System.out.println(count);

count 通常小于 1,000,000。

我在 x86 处理器上运行 - Intel core 2 duo E8400,热点为 1.6.24。与 volatile 变量一起使用的++ 运算符的常见丢失更新参数,目的是实现原子更新,如下所示:线程 1 和 2 都为 v 读取值 0,都将其递增 1 并写入值 1。

在 x86 上使用 volatile 时,这个论点似乎站不住脚,因为:

1) 对 volatile 变量的每次访问都通过 CPU 缓存层次结构。 JVM 可以生成汇编代码来多次访问 volatile,而无需从内存中加载/存储,只有当它可以证明 volatile 变量是由单个线程访问时,但这里不是这种情况。

2) 只有一个 CPU 可以有一个特定的缓存行处于修改状态,所以如果两个 CPU 都尝试增加 v,只有一个会成功地使包含 v 的缓存行进入修改状态。另一个将使其缓存行无效,稍后才会进入修改状态,其缓存包含正确的值 1,并将变量更新为 2。

我在这里错过了什么?

最佳答案

您忽略了++ 不是原子操作这一事实。

如果您将代码重写为:

for (int i=0; i<1000000; i++)
int tmp = count;
tmp = tmp + 1;
count = tmp;
}

这样是不是更清楚了?这里不需要内存模型或高速缓存行的详细信息 - 我们只需要两个线程都读取相同的值,都进行独立的工作,然后都再次存储它们的计算值。

关于java - x86 上的 volatile 怎么会丢失更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8333043/

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