【详解】Java内存模型中 happens-before规则

Java内存模型中 happens-before规则

  1. 如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作课件,并且第一个操作的执行顺序排在第二个操作之前。
  2. 两个操作间存在happens-before关系,不意味着Java平台一定按照被该关系制定的顺序执行,如果重排序后不按照该顺序,但结果一致,那么这种重排序合法。
  1. 程序顺序规则:

    • 一个线程中,按照程序执行的顺序,前面的操作happens-before于后面的操作。
    • 也就是符合单线程的思维,程序在前面对变量的修改对后续操作可见。
  2. 监视器锁规则(管程锁):

    • 一个锁的解锁 Happens-Before 于后续对这个锁的加锁
    • 管程:通用的同步原语,在Java语言中是synchronized的实现
    • synchronized中的加锁解锁操作是隐式的,前一个线程的解锁对后一个线程的加锁可见,这保证了对共享变量的可见性。
  3. volatile变量规则:

    • 对一个volatile域的写,Happens-Before于对该域的读。
  4. 传递性:A Happens-Before B,B Happens-Before C,则A Happens-Before C

    • 结合例子来看:

      class VolatileExample {
               
       int x = 0;
       volatile boolean v = false;
       public void writer() {
               
       x = 42;
       v = true;
       }
       public void reader() {
               
       if (v == true) {
               
      
       }
       }
      }
      
      • 根据规则1:x=42 Happens-Before于 v=true

      • 根据规则3:volatile 修饰的变量v=true的写 Happens-Before 于v=true的读

      • 根据规则4:x=42 Happens-Before 于v=true的读,也就是我们读到的x为42

        避免了多线程中CPU 缓存而导致可见性问题。

  5. start()规则:父线程A中执行了子线程B的ThreadB.start()操作,则该操作 Happens-Before 于线程B中任何操作

    Thread B = new Thread(()->{
           
    });
    // 此处对共享变量 a 修改对B可见
     a = 77;
    // 主线程启动子线程
    B.start();
    
  6. join()规则:线程等待原则,如果在线程 A 中,调用线程 B 的 join() 并成功返回,那么线程 B 中的任意
    操作 Happens-Before 于该 join() 操作的返回

    Thread B = new Thread(()->{
           
     a = 66;
    });
    B.start();
    B.join()
    // 子线程所有对共享变量的修改在主线程调用 B.join() 之后皆可见,A中看到a=66
    
  7. 线程中断规则:对线程interrupt()方法的调用 Happens-Before 于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。

  8. 对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。

你可能感兴趣的:(JUC,基础总结,java,开发语言,后端)