java内存模型的happens-before语义顺序问题?

java内存模型的happens-before语义顺序问题?

注意,两个操作之间具有 happens-before 关系,并不意味着前一个操作必须要在后一个操作之前执行!happens-before 仅仅要求前一个操作(执行的结果)对后 一个操作可见,且前一个操作按顺序排在第二个操作之前(the first is visible to and ordered before the second)。happens- before 的定义很微妙,后文会具 体说明 happens-before 为什么要这么定义。

——引用自《深入理解JAVA内存模型》

这本书后边有一个重排序的例子,说明没有依赖关系的两个语句可以重排,所以“并不意味着前一个操作必须要在后一个操作之前执行”。那“且前一个操作按顺序排在第二个操作之前”这句话的含义又是什么呢

黑色斜体两段字所要表明的意思区别究竟在哪,感觉这两句话是矛盾的呢?能否举例说明一下

关注者

38

被浏览

2,012

关注问题写回答

​邀请回答

​1 条评论

​分享

​举报

收起

4 个回答

默认排序​

钟懒

钟懒

3 人赞同了该回答

It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal.

这是JSR133的原话。

就是说执行a1,a2这两个操作,只要执行结果是跟顺序执行a1,a2的执行结果一样,就是合法的。比如write a = 1, write a = 2; read a;前两个操作可以重排序,但读操作不能和前两个操作重排序。所以其实没有矛盾的。

编辑于 2017-03-27

​赞同 3​​添加评论

​分享

​收藏​感谢

杜双成

杜双成

1 人赞同了该回答

Java内存模型中的happens-before是比较难理解的地方,为什么要提出这样的模型,这个牵制到计算机体系结构的一些知识,由于在计算机系统存在寄存器,L1,L2,L3 等多级缓存,主存储器,所以一个变量可能被存储在计算机内存的不同区域,同时由于线程都对应一个称为工作内存的区域,各个线程从内存总读取变量在各自的工作内存中进行变量的操作,这样就会出现变量不一致的情况,Java编译器为了协调对变量的访问,提出了自己的内存模型;happens-before的规则前后两个操作满足离散数学中的偏序关系, happens-before规则不是描述实际操作的先后顺序,它是用来描述可见性的一种规则 ,也就是说在Java中常见的内置锁synchronized等不仅是保持了同步,更是隐含着保持了内存的可见性,仔细想一想确实是这样的;举一个例子,happen-before中有一条规则称为:在监视器上的解锁操作必须是在同一个监视器的加锁操作之前执行。 如果线程1解锁了monitor a,接着线程2锁定了a,那么,线程1解锁a之前的写操作都对线程2可见(线程1和线程2可以是同一个线程)。 如果线程1写入了volatile变量v(这里和后续的“变量”都指的是对象的字段、类字段和数组元素),接着线程2读取了v,那么,线程1写入v及之前的写操作都对线程2可见(线程1和线程2可以是同一个线程)。 ================》对于你疑问“ 并不意味着前一个操作必须要在后一个操作之前执行 ”,这里说的先后是一种时间上先后,也就是说A操作在时间上先于B操作执行。但是按照happens-before中的8条规则,若不满足其中的任何一条就无法确保两个操作的可见性,编译器将对指令进行重排序;后面的那句“ happens-before 仅仅要求前一个操作(执行的结果)对后 一个操作可见,且前一个操作按顺序排在第二个操作之前 ”这句话的意思是在满足happends-before的8条规则的前提下,在满足可见性的条件下,编译器允许对指令进行重新排序,这么更加利于计算机cpu指令的执行,提升性能,但是在happends-before个约束下,满足可见性,从而保证最终的结果保持一致性。最后我想说明的是,前面提到的偏序概念很重要,如果学过离散数学的话就不难理解了, happen-before关系是个偏序关系。两个存在happen-before关系的操作不可能同时发生,一个操作A happen-before操作B,它们必定在时间上是完全错开的,所以才有那句“ 且前一个操作按顺序排在第二个操作之前 ”,这里的先后不是时间上的先后,而是在happends-before约束下的先后,由于偏序关系要求必须错开执行,不能同时,所以两个操作必定是有顺序的,所以。。。希望你能理解。

编辑于 2017-03-27

​赞同 1​​7 条评论

​分享

​收藏​感谢

wxweven

wxweven

攻城架构狮

我觉得必须要请出R大来详细解释下,以及编译器如何做指令重排序的,坐等R大 

@RednaxelaFX

发布于 2018-02-06

猜你喜欢

转载自blog.csdn.net/evilcry2012/article/details/83750654

相关文章