首先,有两件事
will be flushed to memory-这是非常错误的。几乎永远不会刷新到主内存-
它通常将StoreBuffer消耗到其中,
L1并且取决于缓存一致性协议来在所有缓存之间同步数据, 但是
如果您可以更轻松地从这些角度理解这个概念,那就很好-知道那有点不同,而且更快。
这是一个很好的问题,为什么
[StoreLoad]确实存在,也许这可以使事情有所清除。
volatile的确是关于栅栏的,这里是一个示例,说明在某些不稳定的操作情况下将插入哪些栅栏。例如,我们有一个
volatileload:
// i is some shared volatile field int tmp = i; // volatile load of "i" // [LoadLoad|LoadStore]
注意这里
LoadStore和下面 的两个障碍
LoadLoad。用简单的英语来说,这意味着任何
Load和
Store之后出现的
volatileload/read事物都不能“提升”障碍,它们不能被重新排序为“高于”波动性负载。
这是的示例
volatile store。
// "i" is a shared volatile variable // [StoreStore|LoadStore] i = tmp; // volatile store
这意味着任何
Load并且
Store不能“低于”负载存储本身。
这基本上建立之前发生关系,
volatile load是在 获取负荷 和
volatile store作为 释放店
(这也与如何做
Store和
LoadCPU的缓冲区都实现,但是这几乎是不可能的范围)。
如果您考虑一下,那么对于我们
volatile通常所了解的事情来说,这是完全有意义的;它说,一旦通过易失性负载 观察到 易失性存储, 也将观察到
a之前的所有内容
volatilestore,这与内存障碍是同等的。现在有意义的是,当发生易失性存储时,其上方的所有内容都不能超出其范围,并且一旦发生易失性负载,其下方的所有内容都不能超过其上方,否则这种情况发生之前将被破坏。
但是, 这不是它,还有更多。必须具有 顺序一致性 ,这就是为什么任何明智的实现都将确保挥发物本身不会重新排序的原因,因此又插入了两个篱笆:
// any store of some other volatile // can not be reordered with this volatile load // [StoreLoad] -- this one int tmp = i; // volatile load of a shared variable "i" // [LoadStore|LoadLoad]
还有一个在这里:
// [StoreStore|LoadStore]i = tmp; // volatile store// [StoreLoad] -- and this one
现在,事实证明
x864个内存屏障中有3个是空闲的-因为它是一个
strong memorymodel。唯一需要实现的是
StoreLoad。
ARM例如,在其他CPU上
lwsycn使用的是一条指令-但是我对它们并不了解。
通常 一个
mfence是一个不错的选择
StoreLoad上
x86,但同样的事情是通过保证
lockadd(以较便宜的方式AFAIK),这就是为什么你看到它在那里。基本上是 是 的
StoreLoad屏障。是的-
对于较弱的内存模型,您的最后一句话是正确的-
StoreStore将需要设置障碍。附带说明一下,当您通过
final构造函数内部的字段安全地发布引用时,将使用此注释。退出构造函数后,插入了两个栅栏:
LoadStore和
StoreStore。
精打细算,所有这些-JVM可以随意忽略这些规则,只要不违反任何规则即可:Aleksey Shipilev对此进行了精彩的论述。
编辑
假设您有这种情况:
[StoreStore|LoadStore]int x = 4; // volatile store of a shared "x" variableint y = 3; // non-volatile store of shared variable "y"int z = x; // volatile load[LoadLoad|LoadStore]
基本上没有屏障将阻止
volatile store对被重新排序与
volatile load(即:易失性负载将被执行的 第一
),并且将明显导致问题; 因此违反了顺序一致性。
顺便说一句,如果您没记错的话,您有点错过了这一点
Every action after volatile load won't be reorderedbefore volatile load is visible。 volatile本身 无法进行重新排序-
其他操作可以自由进行重新排序。让我举一个例子:
int tmp = i; // volatile load of a shared variable "i" // [LoadStore|LoadLoad] int x = 3; // plain store int y = 4; // plain store
最后两个操作
x = 3和
y = 4绝对自由地重新排序,他们 不能浮上面的挥发性 ,但它们可以被重新排序通过自己。上面的例子是完全合法的:
int tmp = i; // volatile load // [LoadStore|LoadLoad] // see how they have been inverted here... int y = 4; // plain store int x = 3; // plain store



