java happens before_happens-before规则(JMM)

1

happens-before的概念最初由Leslie Lamport在其一篇影响深远的论文(《Time,Clocks and the Ordering of Events in a Distributed System》)中提出。Leslie Lamport使用happens-before来定义分布式系统中事件之间的偏序关系(partial ordering)。Leslie Lamport在这篇论文中给出了一个 分布式算法,该算法可以将该偏序关系扩展为某种全序关系。 JSR-133使用happens-before的概念来指定两个操作之间的执行顺序。由于这两个操作可以在一个线程之内,也可以是在不同线程之间。因此,JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证。

2

《JSR-133:Java Memory Model and Thread Specification》对happens-before关系的定义如下:

1)如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。注意:这一点仅仅是JMM对程序员的保证

2)两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照happens-before关系指定的顺序来执行。如果重排序之后的执行结果,与按happens-before关系来执行的结果一致,那么这种重排序并不非法(也就是说,JMM允许这种重排序)。

3

1、程序次序规则(Program Order Rule):在一个线程内,书写在前面的操作先行发生于后面的操作。准确的说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支和循环等结构。如下代码示例:1 happens-before 2,3 happens-before 4

bded56f6d7df1302af8501d25a5e669f.png

4

2、volatile 变量规则(Volatile Lock Rule):对于 volatile 修饰的变量的写的操作,一定 happen-before 后续对于volatile变量的读操作。如上顺序规则示例中,因为变量flag加了volatile修饰,所以2 happens-before 3

5

3、传递性规则(Transitivity Rule):如上顺序规则示例中,根据顺序规则:1 happens-before 2;根据volatile变量规则:2 happens-before 3;故而根据传递性规则可以推导出:1 happens-before 3。

6

4、线程启动规则(Thread Start Rule):Thread对象的start()方法,先行发生行于此线程的每一个动作。如下示例中,因为1 happens-before 2,而2又happens-before线程1内的所有操作,所有x的值对线程t1是可见的

c03c1e78d60845a06549b4f7647b2a1a.png

7

5、线程终止原则(Thread Termination Rule):线程中所有操作happens-before于对此线程的终止检测,我们可以通过Thread.join()等手段检测到线程已经终止。如下示例中,因为1 happens-before 2,而2又happens-before 3,所有t1中修改了x的值,对主线程可见

ab608229de56a313df8765ab01de59b6.png

8

6、监视器锁定规则(Monitor Lock Rule):一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须强调的是必须为同一个锁,而“后面”是指的时间上的先后顺序。如下示例,假如线程A先进去执行过一次x++,然后释放锁,然后线程B再进入同步代码块,那么B获得的x为11:

d0c970fb5d0cc5961183184c4858d1ce.png

9

7. 线程中断规则(Thread Interruption Rule):对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,我们可以通过Thread.interrupted()方法检测到是否有中断发生。

8. 对象终结规则(Finalizer Rule):一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法。

10

as-if-serial语义的意思是:不管怎么重排序(编译器和处理器为了提高并行度),单线程程序的执行结果不能被改变。编译器、runtime和处理器都必须遵守as-if-serial语义。为了遵守as-if-serial语义,编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。但是,如果操作之间不存在数据依赖关系,这些操作就可能被编译器和处理器重排序。为了具体说明,请看下面代码示例:

09a9d86d6c0faaca847bb878a49430a6.png

11

上面示例中:1和3之间存在数据依赖关系,同时2和3之间也存在数据依赖关系。因此在最终执行的指令序列中,3不能被重排序到1和2的前面(3排到1和2的前面,程序的结果将会被改变)。但1和2之间没有数据依赖关系,编译器和处理器可以重排序1和2之间的执行顺序。

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值