Java并发编程番外篇(二)happens-before关系
2016-08-21 23:01
573 查看
在Java 并发编程(三)同步中,提到了内存一致性错误,而避免内存一致性错误的关键就是了解happens-before关系。那么什么是happens-before关系呢?如何判断两个操作是否存在happends-before关系呢?本文将来介绍这两个方面。
In computer science, the happened-before relation (denoted: ->) is a relation between the result of two events, such that if one event should happen before another event, the result must reflect that, even if those events are in reality executed out of order (usually to optimize program flow).
简答翻译一下,就是:
在计算机科学领域,happened-before是指两个事件结果的关系(用->表示),如果一个事件发生在另一个事件之前,那么第一个事件的结果必须影响到第二个事件,即使这事件实际并不按顺序执行(通常用来优化程序流程)。
在Java规范中,happened-before保证了语句A内存的写入对语句B是可见的,也就是在B开始读数据之前,A已经完成了数据的写入。
happends-before关系满足传递性、非自反性和非对称性,即:
任意的a,b,c,如果a->b,b->c,那么a->c;
任意的a,a->a永远不会成立。
任意的a,b,如果a->b,那么b->a不会成立。
一个线程中的语句和它之后的语句之间存在happens-before关系;
一个锁的释放(同步块或者方法的退出)和该锁的后续获得(同步块或者方法的进入)存在happens-before关系;
volatile变量的写与该域后续的读操作存在happens-before关系;
开启线程的语句域线程中的语句存在happens-before关系;
线程中的所有操作与该线程join返回的其他线程存在happens-before关系。
java.util.concurrent中的类及其子类的方法保证了高级别的同步,特别是:
任何并发集合的写操作与该集合的后续访问或者删除操作存在happens-before关系;
线程中提交Runnable到Executor之前的代码与Runnable中的代码存在happens-before关系。对提交Callable到ExecutorService也一样;
一个Future代表的异步计算和另一个线程中Future.get()的后续操作存在happens-before关系;
释放同步方法(比如Lock.unlock,Semaphore.release和 CountDownLatch.countDown)之前的代码和随后的在相同对象上的获得方法(比如Lock.lock, Semaphore.acquire, Condition.await和 CountDownLatch.await)存在happens-before关系;
通过Exchanger成功交换对象的线程对,exchange()之前的代码和exchange()之后的代码存在happens-before关系;
调用CyclicBarrier.await和Phaser.awaitAdvance之前的代码和执行barrier操作存在happens-before关系;执行barrier操作和其他线程中对应await返回后的代码存在happens-before关系。
1. happens-before关系
Wikipedia, Happened-before是这样定义的:In computer science, the happened-before relation (denoted: ->) is a relation between the result of two events, such that if one event should happen before another event, the result must reflect that, even if those events are in reality executed out of order (usually to optimize program flow).
简答翻译一下,就是:
在计算机科学领域,happened-before是指两个事件结果的关系(用->表示),如果一个事件发生在另一个事件之前,那么第一个事件的结果必须影响到第二个事件,即使这事件实际并不按顺序执行(通常用来优化程序流程)。
在Java规范中,happened-before保证了语句A内存的写入对语句B是可见的,也就是在B开始读数据之前,A已经完成了数据的写入。
happends-before关系满足传递性、非自反性和非对称性,即:
任意的a,b,c,如果a->b,b->c,那么a->c;
任意的a,a->a永远不会成立。
任意的a,b,如果a->b,那么b->a不会成立。
2. 如何判断happens-before关系
根据Java SE 8 Docs, Memory Consistency Properties,synchronized,volatile,Thread.start()和Thread.join() 方法可以形成happens-before关系,特别是:一个线程中的语句和它之后的语句之间存在happens-before关系;
一个锁的释放(同步块或者方法的退出)和该锁的后续获得(同步块或者方法的进入)存在happens-before关系;
volatile变量的写与该域后续的读操作存在happens-before关系;
开启线程的语句域线程中的语句存在happens-before关系;
线程中的所有操作与该线程join返回的其他线程存在happens-before关系。
java.util.concurrent中的类及其子类的方法保证了高级别的同步,特别是:
任何并发集合的写操作与该集合的后续访问或者删除操作存在happens-before关系;
线程中提交Runnable到Executor之前的代码与Runnable中的代码存在happens-before关系。对提交Callable到ExecutorService也一样;
一个Future代表的异步计算和另一个线程中Future.get()的后续操作存在happens-before关系;
释放同步方法(比如Lock.unlock,Semaphore.release和 CountDownLatch.countDown)之前的代码和随后的在相同对象上的获得方法(比如Lock.lock, Semaphore.acquire, Condition.await和 CountDownLatch.await)存在happens-before关系;
通过Exchanger成功交换对象的线程对,exchange()之前的代码和exchange()之后的代码存在happens-before关系;
调用CyclicBarrier.await和Phaser.awaitAdvance之前的代码和执行barrier操作存在happens-before关系;执行barrier操作和其他线程中对应await返回后的代码存在happens-before关系。
相关文章推荐
- Java多线程:volatile变量、happens-before关系及内存一致性
- Java并发编程番外篇(三)volatile变量、happens-before与内存一致性错误
- java.util.concurrent包介绍(3)——Happens-before法则
- Java并发11:Java内存模型、指令重排、内存屏障、happens-before原则
- happens-before规则和as-if-serial语义
- 基于Happens-before的数据竞争方法汇总 (三)
- Java多线程系列-happens-before规则和as-if-serial语义
- .after()和.before()的关系
- Java中构造代码块和成员变量初始化的顺序关系2之 Cannot reference a field before it is defined
- Java Happens-before法则
- happens-before规则
- happens-before俗解
- 多线程 happens-before规则
- 【并发】死磕Java并发:Java内存模型之happens-before
- happens-before俗解
- Java 多线程之happens-before规则解释
- happens-before
- happens-before
- happens_before
- 基于Happens-before的数据竞争方法汇总 (二)