happens-before | as-if-serial | 重排序 (一)

happen-before不光指A发生在B之前,更重要的是要知道它是一个原则,它让A的结果在B之前出现,即B能够看到A对数据进行的操作

(言下之意,时间先后顺序与先行发生原则之间基本没有太大的关系,所以我们衡量并发安全问题的时候不要受到时间顺序的干扰,一切以先行发生原则为准)

 

从底层原理上理解上面括号里这句话:

在程序运行过程中,所有的变更会先在寄存器或本地cache中完成,然后才会被拷贝到主存以跨越内存栅栏(或者叫内存屏障,即是从线程的工作内存到主内存的拷贝动作,在多线程并发过程中,仅当写操作线程先跨越内存栅栏而读线程后跨越内存栅栏的情况下,写操作线程所做的变更才对其他线程可见),此种跨越序列或顺序称为happens-before。

注:happens-before本质是顺序,重点是跨越内存栅栏

通常情况下,写操作必须要happens-before读操作,即写线程需要在所有读线程跨越内存栅栏之前完成自己的跨越动作,其所做的变更才能对其他线程可见。

 

happen-before中有八条保证happen-before的规则,这八条是JMM会遵守的(这里的遵守是指:要么 (1)你什么都不需要添加,直接遵守(例如第一条:程序次序规则), 要么 (2)你使用一些关键字,例如synchronized、volatile,JMM就懂了,就会按相应规则去执行), 它们无需任何同步器协助就已经存在(某些规则需要自己加上关键字才能使用,例如synchronized、volatile)。

 

1)程序次序规则:在一个线程内(注意:只能在单线程中,这条规则才有效),按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作(但是并不是禁止指令重排而实现的)。准确地说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。

( 对于程序次序规则来说,我的理解就是一段程序代码的执行在单个线程中看起来是有序的。注意,虽然这条规则中提到“书写在前面的操作先行发生于书写在后面的操作”,这个应该是程序看起来执行的顺序是按照代码顺序执行的,因为虚拟机可能会对程序代码进行指令重排序。虽然进行重排序,但是最终执行的结果是与程序顺序执行的结果一致的,它只会对不存在数据依赖性的指令进行重排序。因此,在单个线程中,程序执行看起来是有序执行的,这一点要注意理解。事实上,这个规则是用来保证程序在单线程中执行结果的正确性,但无法保证程序在多线程中执行的正确性。)

(happen-before中的程序次序规则保证了as-if-serial语义): 不管怎么重排序(编译器和处理器为了提供并行度),(单线程)程序的执行结果不能被改变,as-if-serial为程序员创建了一个幻觉:单线程程序是按程序的顺序来执行的)

(恰好也印证了程序次序规则是针对单线程的!!!)

 

(as-if-serial与happens-before的区别:

1.as-if-serial语义保证单线程内程序的执行结果不被改变,happens-before关系保证正确同步的多线程程序的执行结果不被改变。

2.as-if-serial语义给编写单线程程序的程序员创造了一个幻境:单线程程序是按程序的顺序来执行的。happens-before关系给编写正确同步的多线程程序的程序员创造了一个幻境:正确同步的多线程程序是按happens-before指定的顺序来执行的。

3.as-if-serial语义和happens-before这么做的目的,都是为了在不改变程序执行结果的前提下,尽可能地提高程序执行的并行度。)

 

2)管程锁定:一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须强调的是同一个锁,而“后面”是指时间上的先后顺序。

3)volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的“后面”同样是指时间上的先后顺序。

4)线程启动规则:线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。

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

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

7)传递性:如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。

 

最后读下来,感觉:happens-before规则里面保证了as-if-serial语义,具体来说是happens-before的第一条规则(即1)程序次序规则)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值