您的位置:首页 > 编程语言 > Java开发

java内存模型中的先行发生原则

2016-09-12 22:33 399 查看

先行发生原则

前言

由上一篇,我们知道并发问题的一个原因是有序性,而java中volatile和synchronized可以保证有序性;

但是在java中,并不是所有的操作都是由volatile和synchronized实现的,java中存在”先行发生“的原则。

“先行发生”原则是判断数据是否存在竞争、线程是否安全的主要依据;

什么是先行发生原则?

先行发生原则是指:如果说操作A先行发生于操作B,也就是发生在操作B之前,操作A产生的影响能被操作B观察到。

举例说明:

//以下操作在线程A中执行
i = 1;
//以下操作在线程B中执行
j = i;
//以下操作在线程C中执行
i = 2;


假设线程A中的操作i=1先行发生于线程B的操作j=i,那么可以确定在线程B的操作执行之后,j一定等于1。因为:根据先行发生原则,i=1的结果可以被B观察到;

现在保持A先行发生于B,线程C出现在A与B之间,但是线程C与B没有先行发生关系。那么j会等于多少呢?答案至不确定。因为线程C对变量i的影响可能会被B观察到,也可能不会。因为两者之间没有先行发生关系;

====》先行发生原则就是操作A在时间上或者逻辑上比B先发生,那么B一定能看到A操作带来的影响(修改了共享变量的值等等),那么此时A就是先行发生于B。

你可能会说难道B还有可能不会看到A带来的影响吗?A操作先执行的呀!想一想我们上面提到的内存可见性和有序性…

java内存模型中的”天然“先行关系

1、程序次序规则

一个线程内,按照程序代码的顺序,书写在前面的操作先行发生于(逻辑上)书写在后面的操作。

2、管程锁定规则

一个unlock操作先行发生于后面对同一个锁的lock操作。后面指时间上的先后顺序。

3、volatile变量规则

对一个volatile变量的写操作先行发生于后面对这个变量的读操作。这里的后面指时间上的先后顺序。

4、传递性

如果操作A先行发生于操作B,操作B先行发生于操作C,那么,操作A也就先行发生于操作C。

5、线程启动规则

Thread对象的start方法先行发生于此线程的每个动作;

6、线程终止规则

线程中的所有操作都先行发生于对此线程的终止检测;

7、线程中断规则

对线程的interrupt()方法的调用先行发生于被中断线程的代码检测到中断时间的发生;

8、对象终结规则

一个对象的初始化完成先行发生于它的finalize方法的开始;

。。。。。

java无须任何手段即可保证上面的先行发生规则成立;

分析

先行发生原则(happens-before)不是描述实际操作的先后顺序,它是用来描述可见性的一种规则;

对上述中原则的理解:

对2)管程锁定规则的理解:如果线程1解锁了a,接着线程2锁定了a,那么,线程1解锁a之前的写操作都对线程2可见(线程1和线程2可以是同一个线程)。

对3)volatile变量规则的理解:如果线程1写入了volatile变量v(这里和后续的“变量”都指的是对象的字段、类字段和数组元素),接着线程2读取了v,那么,线程1写入v及之前的写操作都对线程2可见(线程1和线程2可以是同一个线程)。

总结

先行发生原则的作用:判断内存可见性与重排序是否造成并发问题。

参考:

http://ifeve.com/easy-happens-before/

http://yukai.space/2016/09/10/%E7%90%86%E8%A7%A3java%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  并发