您的位置:首页 > 移动开发

Java并发编程番外篇(二)happens-before关系

2016-08-21 23:01 573 查看
Java 并发编程(三)同步中,提到了内存一致性错误,而避免内存一致性错误的关键就是了解happens-before关系。那么什么是happens-before关系呢?如何判断两个操作是否存在happends-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 并发 编程