乐趣区

关于java:Java内存模型之happensbefore原则

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 中十分重要的准则,它是判断数据是否存在竞争、线程是否平安的次要根据,保障了多线程环境下的可见性。

退出移动版