【发布时间】:2013-02-27 22:17:38
【问题描述】:
在 Java 中,当我们有两个线程共享以下变量时:
int a;
volatile int b;
如果线程 1 这样做:
a = 5;
b = 6;
然后在这两条指令之间插入一个 StoreStore 屏障,并将“a”刷新回主内存。
现在如果线程 2 这样做:
if(b == 6)
a++;
在两者之间插入了一个LoadLoad屏障,我们保证如果'b'的新值是可见的,那么'a'的新值也是可见的。但实际上这是如何实现的呢? LoadLoad 是否会使 CPU 缓存/寄存器无效?还是只是指示 CPU 从 CPU 再次读取 volatile 之后的变量值?
我找到了有关 LoadLoad 屏障 (http://gee.cs.oswego.edu/dl/jmm/cookbook.html) 的信息:
LoadLoad Barriers 顺序:Load1;加载加载; Load2 确保 Load1 的数据在 Load2 访问的数据之前加载,所有 随后的加载指令被加载。通常,显式 LoadLoad 执行推测加载的处理器需要屏障 和/或乱序处理,其中等待加载指令可以 绕过等候商店。在保证始终保留的处理器上 加载排序,障碍相当于无操作。
但它并没有真正解释这是如何实现的。
【问题讨论】:
-
答案取决于处理器架构 - 同一份文档有一个表格,其中包含每个处理器指令,例如,
LoadLoad是 x86 上的无操作。 -
那么它到底是如何工作的呢?我的意思是,在 StoreStore 之后,值会被刷新回内存中。但是线程 2 应该如何看到它们呢?如果 LoadLoad 计算结果为无操作,则线程 2 可以继续使用缓存值。
-
因为处理器的内存模型足够强大,可以保证它会是这种情况。我想说的是,Java 承诺如果您使用 volatile,某些事情将会/不会发生。这是如何在 JVM 中实现的,是特定于处理器的,并使用临时指令(如果相关,也可以不使用指令)。您可以在此处阅读有关 LoadLoad/x86 点的更多信息:altair.cs.oswego.edu/pipermail/concurrency-interest/2012-July/…
-
您可以进一步了解 LoadLoad 不是无操作的 CPU 架构,例如 ARM。不过似乎很重的东西:)
标签: java concurrency volatile