StoreStore Barriers序列:Store1; StoreStore; Store2确保 Store1的数据对其他处理器可见(即刷新到 内存)在与Store2和所有后续关联的数据之前 商店说明。通常,需要StoreStore障碍 处理器,否则不保证严格的刷新顺序 从写入缓冲区和/或缓存到其他处理器或主存储器。
而且,从食谱中我们知道,对于同步块,Java编译器会插入一些障碍以防止可能的重新排序:
MonitorEnter
[LoadLoad] <==inserted barrier
[LoadStore]<==inserted barrier
...
[LoadStore]<==inserted barrier
[StoreStore]<==inserted barrier
MonitorExit
但是,由于x86不允许重新读取读 - 读,读 - 写和写 - 写。因此,所有上述障碍都将映射到no-ops.That相当于说在MonitorEnter和MonitorExit之间不会为x86处理器插入障碍。 我的困惑是,如果我们将StoreStore映射到x86下的no-op,那么可见性如何保证? 更详细地说,x86 DOES使用存储缓冲区,因此为了使临界区中执行的写操作对其他处理器可见,我们需要刷新存储缓冲区,因此需要写入屏障。从可见性的角度来看,应该映射到sfence / mfence / Lock#?但是食谱说它应该从重新排序预防的角度映射到无操作。 或者,关键点是可见性保证由MonitorEnter和 MonitorExit本身?如果是这种情况,我认为他们可能会使用所谓的Read barrier和Write barrier来保证可见性,对吗?
答案 0 :(得分:0)
虽然我们可以说记忆障碍能够:
但这并不意味着内存屏障应该总是将上述两件事情放在一起,Sun JDK提供的Unsafe.doPutOrderedXX方法就是这样一个例子:
SomeClass temp = new SomeClass(); //S1
unsafe.putOrderedObject(this, valueOffset, null);
Object target = temp; //S2
unsafe.putOrderedObject在这里用作StoreStore屏障,因此可以防止 重新排序S1和S2,但它不保证S1的结果对其他处理器/线程可见(因为没有这样的需要)。
有关不安全和不稳定的更多信息:
http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/
http://jpbempel.blogspot.com/2013/05/volatile-and-memory-barriers.html
在x86下,为了防止重新排序的目的enter code here
,StoreStore可以映射到no-op,为了可见性保证,StoreStore应该映射到某些像sfence / mfence / LOCK#。这样的说明。
另一个例子是final关键字。要强制执行 final 的语义(观察到的变量的值不能更改),编译器应在写入 final 字段之间插入StoreStore屏障并从中返回构造函数。这样做的原因是:确保在将构造对象的引用写入引用变量之前,对 final 字段的写入应对其他处理器可见。实际上,这意味着需要排序而不是可见性,因此在返回之前写入最终刷新(刷新存储缓冲区/缓存)的结果是不从那个构造函数。因此,在x86下,JVM不会为最终字段插入任何障碍。