Happens-Before规则是什么?

52 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

JMM happens-Before:用来保障两个操作之间的可见性,这两个操作可以在一个线程,也可以在不同线程。从JDK 5 开始,JMM就使用happens-before的概念来阐述多线程之间的内存可见性。

很熟悉吧?volatile的禁止指令重排就跟这个有关。 volatile的可见性和禁止指令重排序怎么实现的?

具体定义∶

  1. 如果一个操作 happens-before 另一个操作,那么第一个操作的执行结果,将对第二个操作可见。(保障可见性)

    • 而且第一个操作的执行顺序排在第二个操作之前。(JMM对程序员做出的一个逻辑保障,并不是代码指令真正的执行保障)
  2. 即使两个操作之间存在happens-before关系,并不意味着Java 平台的实现必须要按照happens-before关系指定的顺序来执行。

因此,第一条是JMM对程序员做出的一个逻辑保障;第二条是JMM对编译器、处理器进行重排序的约束原则︰只要不改变程序的执行结果(不管是单线程、还是多线程),编译器、处理器怎么优化都可以

规则

  1. 程序顺序规则:一个线程中的每一个操作,happens-before于该线程中的任意后续操作。(程序中必须按照顺序执行)
 int a = 5;
 int c = a + 1;  // c必须发生在后面,也就是c = 6;
  1. 监视器规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。(只有前一个锁解锁了,后一个锁才能加锁)

  2. volatile规则:对一个volatile变量的写,happens-before于任意后续对一个volatile变量的读。(volatile变量的写操作一定优先于后一个读操作--写操作会强行刷回主内存,让其他线程持有的这个变量拷贝备份失效)

  3. 传递性:若果A happens-before B,B happens-before C,那么A happens-before C。

      int a = 5;
      int b = 6;
      int c = a + 1;  // a在b前面,b在c前面,所以传递成a在c前面;
  1. 线程启动规则:Thread对象的start()方法,happens-before于这个线程的任意后续操作。(如果在线程A里面去执行了线程B的start,那么在线程A里面的 B.start()操作happens-before 线程B中的任意操作)

  2. 线程终止规则:线程中的任意操作,happens-before于该线程的终止监测。我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。(join规则︰如果线程A执行了线程B.join(),那么 线程B中的任意操作happens-before 线程A执行了线程Bjoin()之后的操作)

  3. 线程中断操作:对线程interrupt()方法的调用,happens-before于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到线程是否有中断发生。

  4. 对象终结规则:一个对象的初始化完成,happens-before于这个对象的finalize()方法的开始。

    • finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。