Java多线程 - Happens-Before 规则

总结

Java 为了让大家理解JMM(java memory model, java内存模型)中“内存可见性”的这个概念,􏰀提出了 happens-before 的概念。

如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在 happens-before 关系

两个操作之间具有 happens-before 关系,并不意味着前一个操作必须要在后 一个操作之前执行!

happens-before 仅仅要求前一个操作(执行的结果)对后一个操作可见

 

1)站在 Java 程序员的角度来说: JMM 保证,如果一个操作 happens-before 另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作 的执行顺序排在第二个操作之前。

2)站在编译器和处理器的角度来说: JMM 允许,两个操作之间存在 happens-before 关系,不要求 Java 平台的具体实现必须要按照 happens-before 关系指定的顺序来执行。如果重排序之后的执行结果,与按 happens-before 关系 来执行的结果一致,那么这种重排序是允许的。

 

例子

page126image14243104
 

站在我们 Java 程序员的角度有三个依赖关系:

page126image14242896

 

但是仔细考察,2、3 是必需的,而 1 并不是必需的,因此 JMM 对这三个 happens-before 关系的处理就分为两类:

  1. 会改变程序执行结果的重排序 (在这里指的是,依赖关系2+3)
  2. 不会改变程序执行结果的重排序(在这里指的是,依赖关系1)

JMM 对这两种不同性质的重排序,采用了不同的策略,如下:

  1. 对于会改变程序执行结果的重排序,JMM 要求编译器和处理器必须禁止这 种重排序;
  2. 对于不会改变程序执行结果的重排序,JMM 对编译器和处理器不做要求。

于是,站在我们程序员的角度,看起来这个三个操作满足了 happens-before 关系,而站在编译器和处理器的角度,进行了重排序,而排序后的执行结果,也 是满足 happens-before 关系的。

 

happens-before 关系本质上和 as-if-serial 语义是一回事:

  • as-if-serial 语义保证单线程内程序的执行结果不被改变
  • happens-before 关系保证正确同步的多线程程序 的执行结果不被改变

 

Happens-Before 规则

  • 程序次序规则:在一个线程内,按照程序控制流顺序,书写在前面的操作先行发生于书写在后面的操作
  • 管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作
  • volatile变量规则:对一个volatile变量的写操作,先行发生于后面对这个变量的读操作
  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作
  • 线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测
  • 线程中断规则:对线程interrupt()方法的调用,先行发生于被中断线程的代码检测到中断事件的发生
  • 对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始
 

posted on 2020-09-15 23:00  frank_cui  阅读(379)  评论(0编辑  收藏  举报

导航

levels of contents