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/
相关文章推荐
- 探究在C++程序并发时保护共享数据的问题
- PHP通过加锁实现并发情况下抢码功能
- 在ASP.NET 2.0中操作数据之四十八:对SqlDataSource控件使用开放式并发
- 在ASP.NET 2.0中操作数据之二十一:实现开放式并发
- Nodejs实战心得之eventproxy模块控制并发
- 并发环境下mysql插入检查方案
- Java并发控制机制详解
- PHP编程中尝试程序并发的几种方式总结
- 浅析PHP中Session可能会引起并发问题
- php session的锁和并发
- Oracle 数据库针对表主键列并发导致行级锁简单演示
- Yii+MYSQL锁表防止并发情况下重复数据的方法
- MySQL中SELECT+UPDATE处理并发更新问题解决方案分享
- Java并发编程中的生产者与消费者模型简述
- Java多线程和并发基础面试题(问答形式)
- Java中同步与并发用法分析
- Java多线程编程中的两种常用并发容器讲解
- Shiro 控制并发登录人数限制及登录踢出的实现代码
- Java实现的并发任务处理实例
- Java线程并发中常见的锁机制详细介绍