Happens-beofre 先行发生原则(JVM 规范)

简介: Happens-beofre 先行发生原则(JVM 规范)

如果JMM中所有的有序性都只靠volatile和synchronized,那么有一些操作将会变得很繁琐,但我们在编写Java并发代码时并没有感到这一点,这是因为Java语言中有一个先行发生(Happen-Before)原则


这个原则非常重要,它是判断数据是否存在竞争,线程是否安全的主要依赖。

先行发生原则

指的是JMM中定义的两项操作之间的依序关系

happens- before关系 主要用于强调两个有冲突的动作之间的顺序,以及定义数据争用的发生时机

如果说操作A先行发生于操作B,就是在说发生B前,A产生的影响能被B观察到,“影响”包含了修改内存中共享变量的值、发送了消息、调用了方法等。意味着什么呢?如下例:

//线程A中执行  
i = 1;  
//线程B中执行  
j = i;  
//线程C中执行  
i = 2;

下面是JMM下一些”天然的“先行发生关系,无须任何同步器协助就已经存在,可以在编码中直接使用

如果两个操作之间的关系不在此列,并且无法从下列规则推导出来的话,它们就没有顺序性保障,虚拟机可以对它们进行随意地重排序

具体的虚拟机实现,有必要确保以下

八大原则

  • 程序次序规则(Pragram Order Rule)
    在一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确地说应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环结构。

对象锁(监视器锁)法则(Monitor Lock Rule )

某个 管程(也叫做对象锁,监视器锁) 上的unlock动作happens-before同一个管程上后续的lock动作 。这里必须强调的是同一个锁,而”后面“是指时间上的先后。

volatile变量规则(Volatile Variable Rule)

对某个volatile字段的写操作happens- before每个后续对该volatile字段的读操作,这里的”后面“同样指时间上的先后顺序。

线程启动规则(Thread Start Rule)

在某个线程对象 上调用start()方法happens- before该启动了的线程中的任意动作

线程终止规则(Thread Termination Rule)

某线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束(任意其它线程成功从该线程对象上的join()中返回),Thread.isAlive()的返回值等作段检测到线程已经终止执行。

线程中断规则(Thread Interruption Rule)

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

对象终结规则(Finalizer Rule)

一个对象初始化完成(构造方法执行完成)先行发生于它的finalize()方法的开始

传递性(Transitivity)

如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论

一个操作”时间上的先发生“不代表这个操作会是”先行发生“,那如果一个操作”先行发生“是否就能推导出这个操作必定是”时间上的先发生“呢?也是不成立的,一个典型的例子就是指令重排序

所以时间上的先后顺序与先行发生原则之间基本没有什么关系,所以衡量并发安全问题一切必须以先行发生原则为准。


上面八条是原生Java满足Happens-before关系的规则,但是我们可以对他们进行推导出

其他满足happens-before的案例

  • 将一个元素放入一个线程安全的队列的操作Happens-Before从队列中取出这个元素的操作

将一个元素放入一个线程安全容器的操作Happens-Before从容器中取出这个元素的操作

在CountDownLatch上的倒数操作Happens-Before CountDownLatch#await()操作

Semaphore:release许可的操作Happens-Before acquire许可 的操作

CyclicBarrier:线程中调用 await() 之前的操作 happen-before 那些是屏障操作的一部份的操作,后者依次 happen-before 紧跟在从另一个线程中对应 await() 成功返回的操作。

Future表示的任务的所有操作Happens-Before Future#get()操作

向Executor提交一个Runnable或Callable的操作Happens-Before任务开始执行操作


目录
相关文章
|
2月前
|
安全 项目管理
一文搞懂需求流程规范的制定方法和落地技巧
随着业务和产品的发展、团队的不断扩大,很多团队都不可避免的会遇到需求流程混乱的问题。虽然有的团队也编写了一些“需求流程规范”的文档,但最终却流于纸面,难以在团队真正落地。如何科学制定并有效落实需求管理规范呢?对此,云效产品经理陈逊进行了非常详细的直播分享,本文是他经验的文字总结。
100701 19
|
11月前
|
安全 Java 调度
多线程并发的一些常见的使用规范
多线程并发的一些常见的使用规范
128 0
|
设计模式 测试技术 程序员
代码的简单设计五原则
代码的简单设计五原则
33047 1
|
存储 安全 Java
你认同JVM中先行发生原则是比较隐蔽和重要的一点吗
你认同JVM中先行发生原则是比较隐蔽和重要的一点吗
61 0
|
安全 Java
Java的先行发生原则
先行发生原则(Happens-Before)是Java内存模型定义的一个等效判断原则。依赖这个原则,我们可以通过几条简单规则判断数据是否存在竞争,线程是否安全,而不需要陷入Java内存模型苦涩难懂的定义之中。
|
测试技术
测试思想-流程规范 用例优先级定义与使用规范 V1.0
测试思想-流程规范 用例优先级定义与使用规范 V1.0
119 0
|
设计模式 前端开发 关系型数据库
本着什么原则,才能写出优秀的代码? (二)
本着什么原则,才能写出优秀的代码? (二)
185 0
本着什么原则,才能写出优秀的代码? (二)
|
SQL 程序员 测试技术
本着什么原则,才能写出优秀的代码? (一)
本着什么原则,才能写出优秀的代码? (一)
139 0
本着什么原则,才能写出优秀的代码? (一)
|
设计模式 Java 程序员
怎样才能写出规范的好代码?
最近发现一件事情,自己写的代码和公司里工作5到10年的前辈写的代码虽然功能一样,但是他们的代码更规范,更优雅。比如有时候我会给一个需求写一个方法,但是有些人就可以好几个需求通过同一个方法实现。因此有了今天这个疑问,怎样才能写出规范的好代码?
|
Java
【Java 并发编程】指令重排序规范 ( happens-before 先行发生原则 )
【Java 并发编程】指令重排序规范 ( happens-before 先行发生原则 )
179 0