什么是happens-before原则?

简介: 什么是happens-before原则?

正文

happens-before 关系是用来描述两个操作的内存可见性的。如果操作 X happens-before 操作 Y,那么 X 的结果对于 Y 可见。 Java 内存模型底层是通过内存屏障(memory barrier)来禁止重排序的。


线程内的happens-before


在同一个线程中,字节码的先后顺序(program order)也暗含了 happens-before 关系:在程序控制流路径中靠前的字节码 happens-before 靠后的字节码。

然而,这并不意味着前者一定在后者之前执行。实际上,如果后者没有观测前者的运行结果,即后者没有数据依赖于前者,那么它们可能会被重排序。


线程间的 happens-before


  1. 解锁操作 happens-before 之后(这里指时钟顺序先后)对同一把锁的加锁操作。
  2. volatile 字段的写操作 happens-before 之后(这里指时钟顺序先后)对同一字段的读操作。
  3. 线程的启动操作(即 Thread.starts()) happens-before 该线程的第一个操作。
  4. 线程的最后一个操作 happens-before 它的终止事件(即其他线程通过 Thread.isAlive() 或 Thread.join() 判断该线程是否中止)。
  5. 线程对其他线程的中断操作 happens-before 被中断线程所收到的中断事件 (即被中断线程的 InterruptedException 异常,或者第三个线程针对被中断线程的 Thread.interrupted 或者 Thread.isInterrupted 调用)。
  6. 构造器中的最后一个操作 happens-before 析构器的第一个操作。


happens-before关系的传递性


如果操作 X happens-before 操作 Y,而操作 Y happens-before 操作 Z,那么操作 X happens-before 操作 Z。


内存屏障(memory barrier)


对于即时编译器来说,它会针对前面提到的每一个 happens-before 关系,向正在编译的目标方法中插入相应的读读、读写、写读以及写写内存屏障。

这些内存屏障会限制即时编译器的重排序操作。

即时编译器将根据具体的底层体系架构,将这些内存屏障替换成具体的 CPU 指令。

以我们日常接触的 X86_64 架构来说,读读、读写以及写写内存屏障是空操作(no-op),只有写读内存屏障会被替换成具体指令。

对于即时编译器来说,内存屏障将限制它所能做的重排序优化。对于处理器来说,内存屏障会导致缓存的刷新操作。


volatile 字段禁止指令重排序的底层原理


以 volatile 字段访问为例,所插入的内存屏障将不允许 volatile 字段写操作之前的内存访问被重排序至其之后;

也将不允许 volatile 字段读操作之后的内存访问被重排序至其之前。


相关文章
|
设计模式 测试技术 程序员
代码的简单设计五原则
代码的简单设计五原则
33087 1
|
数据库
软件设计原则
软件设计原则
|
设计模式 算法
软件设计的原则
软件设计的原则
91 0
|
设计模式 安全 Java
软件设计原则有哪些(上)
软件设计原则有哪些(上)
137 0
|
设计模式
软件设计原则有哪些(下)
软件设计原则有哪些(下)
84 0
|
程序员 测试技术
面向对象设计五个基本原则
只有聪明人才能看见的简介~( ̄▽ ̄~)~
102 0
|
设计模式 数据可视化 测试技术
软件设计原则讲解,昭昭在目!
本文主要介绍 软件的设计原则
151 0
|
设计模式 Java 程序员
代码设计原则
代码设计原则
385 0
代码设计原则
|
设计模式 前端开发 关系型数据库
本着什么原则,才能写出优秀的代码? (二)
本着什么原则,才能写出优秀的代码? (二)
208 0
本着什么原则,才能写出优秀的代码? (二)
|
SQL 程序员 测试技术
本着什么原则,才能写出优秀的代码? (一)
本着什么原则,才能写出优秀的代码? (一)
161 0
本着什么原则,才能写出优秀的代码? (一)