Java内存模型之happens-before原则

jacheut / 92 /

ChatGPT 可用网址,仅供交流学习使用,如对您有所帮助,请收藏并推荐给需要的朋友。
https://ckai.xyz

Happens-Before 是一种可见性模型,也就是说,在多线程环境下。

原本因为指令重排序的存在会导致数据的可见性问题,也就是 A 线程修改某个共享变量 对 B 线程不可见。

因此,JMM 通过 Happens-Before 关系向开发人员提供跨越线程的内存可见性保证。

如果一个操作的执行结果对另外一个操作可见,那么这两个操作之间必然存在 Happens-Before 关系。

其次,Happens-Before 关系只是描述结果的可见性,并不表示指令执行的先后顺序, 也就是说 只要不对结果产生影响,仍然允许指令的重排序。

happens-before原则定义如下:

1. 如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。

2. 两个操作之间存在happens-before关系,并不意味着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序并不非法。

JMM中的happens-before原则:

  1. 程序次序规则:一个线程中的每个操作, happens-before 这个线程中的任意后续操作;这个规则只对单线程有效,在多线程环境下无法保证正确性。
  2. 监视器锁规则:一个线程对于一个锁的释放锁操作, 一定 happens-before 于后续线程对这个锁的加锁操作;
  3. volatile变量规则:对一个 volatile 修饰的变量的写一定 happens-before 于任意后续对这个 volatile 变量的读操作;
  4. 传递规则:如果A happens-before B,且B happens-before C,那么A happens-before C。
  5. 线程启动规则:如果线程 A 执行操作 ThreadB.start(),那么线程 A 的 ThreadB.start()之前的操作 happens-before 线程 B 中的任意操作;
在这样一个场景中,t1 线程启动之前对于 x=10 的赋值操作,t1 线程启动以后读取 x 的值一定是 10
  1. 线程终结规则(join 规则):如果线程 A 执行操作 ThreadB.join()并成功返回,那么线程 B 中的任意操作 happens-before 于线程 A 从 ThreadB.join()操作成功的返回。;

(假定线程A在执行的过程中,通过制定ThreadB.join()等待线程B终止,那么线程B在终止之前对共享变量的修改在线程A等待返回后可见。)

  1. 线程中断规则:对线程interrupted()方法的调用先行于被中断线程的代码检测到中断事件的发生。
  2. 对象终结规则:一个对象的初始化完成(构造函数执行结束)先行于发生它的finalize()方法的开始。

happen-before原则是JMM中非常重要的原则,它是判断数据是否存在竞争、线程是否安全的主要依据,保证了多线程环境下的可见性。


Java内存模型之happens-before原则
作者
jacheut
许可协议
CC BY 4.0
发布于
2023-09-24
修改于
2024-07-24
Bonnie image
尚未登录