1

考虑以下情况

Case 1: 
action#1
volatile read var  1
volatile write var 1
volatile read var  2 
volatile write var 2 
action#2

对于上面的案例 1,我们可以说用 action#2 对 action#1 进行重新排序

Case 2:
action#1
synchronized(new Object()){}
synchronized(new Object()){}
action#2

对于上面的案例 2,我们可以对 action#1 和 action#2 的重新排序说些什么。

对于案例 2,我已经得到了问题的答案 Is this a better version of Double Check Locking without volatile and synchronization overhead。这个问题的答案说在 action#2 和 action#1 之间可以进行 case 2 重新排序,因为 JMM 较弱模型比罗奇汽车旅馆模型。我认为 zhong.j.yu 是对的。

但是现在我从以下问题 Valid reorderings - under new JMM的答案中得到了一些矛盾的东西。其中显示了一个有点严格的罗奇汽车旅馆模型。

  For Orignal Code

     instanceVar1 = value ;//  normal read operation, no volatile
     synchronized(this) {
       instanceVar2 = value2; //normal read operation, no volatile   
     }
     instanceVar3 = value3;  //normal read operation, no volatile 

The below Ordering is not possible

Case 4: 

    instanceVar3 = value3;  //normal read operation, no volatile
    synchronized(this) {
       instanceVar2 = value2; //normal read operation, no volatile   
     }
    instanceVar1 = value ;//  normal read operation, no volatile

这也来自 jeremy manson 博客文章 http://jeremymanson.blogspot.co.uk/2007/05/roach-motels-and-java-memory-model.html

另外我想指出编译器在优化涉及内存屏障的代码时受到限制。请参阅:http: //jeremymanson.blogspot.in/2009/06/volatile-arrays-in-java.html 其中** arr=arr 冗余读取和写入未优化,因为 arr 是易失性参考**。

我想说的是,问题的答案在本质上几乎没有矛盾,而且似乎都是正确的。问题 1:有效的重新排序 - 在新的 JMM 下 问题 2:这是没有 volatile 和同步开销的更好版本的 Double Check Locking

我们将如何确定 JMM 在哪一点比 Roach 汽车旅馆模型弱?

4

2 回答 2

3

我认为您正在处理大量无关信息。出于所有实际目的,JMM 与 Roach Motel 模型一样强大。情况 2 中的一个小例外只是因为任何其他线程显然不可能获得锁,所以整个synchronized块只是一个镇流器。JVM 可以假装它从未见过它。

JVM 必须保证的是,在按程序顺序写入 volatile 之前的所有写操作必须可以被另一个读取 volatile 值的线程观察到(类似的保证分别适用于锁定释放/获取操作)。除非您是 JIT 编译器实现者,否则在实践中如何确保这一点只是一个小细节。

于 2013-07-08T20:01:17.647 回答
3

问题一:

另一个很好的参考点是Reodering Grid(我经常在这里参考)。它所说的在这里很有用的是 aNormalLoad后面跟着 aMonitorExit不能重新排序。在这种情况下,instanceVar1 = value ;无法将正常负载重新排序到监视器出口synchronized(this) {

问题2:

从表面上看,它确实显得矛盾。但它真正的意思是,因为没有其他线程可以与一个对象同步(因为你正在这样做new Object),所以有理由认为不需要担心多线程,因此能够删除和重新排序synchronized方法 。

这是基于 Lock Elision 背后的想法。


易失性自引用读/写-据我所知,即使易失性存储与自身一起存储,也不会删除死代码,因此编译器仍然需要遵守易失性存储的排序规则。

于 2013-07-08T20:01:58.130 回答