JMM详解:happents-before原则
目录
参考:
# JMM详解:happents-before原则
Happen-Before
关系是用来解决可见性问题的:如果一个操作 happens-before
于另一个操作,那么我们说第一个操作对于第二个操作是可见的,也就是第二个操作在执行时就一定能保证看见第一个操作执行的结果。
# 8 条 Happens-before 规则
(1)程序次序规则(Program Order Rule):在一个线程内,按照控制流顺序,书写在前面的操作先行发生(Happens-before)于书写在后面的操作。注意,这里说的是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。
(2)管程锁定规则(Monitor Lock Rule):一个 unlock
操作先行发生于后面对同一个锁的 lock
操作。这里必须强调的是 「同一个锁」,而 「后面」是指时间上的先后。
举个例子:
synchronized (this) { // 此处自动加锁
if (x < 1) {
x = 1;
}
} // 此处自动解锁
2
3
4
5
根据管程锁定规则,假设 x 的初始值是 10,线程 A 执行完代码块后 x 的值会变成 1,执行完自动释放锁,线程 B 进入代码块时,能够看到线程 A 对 x 的写操作,也就是线程 B 能够看到 x = 1。
(3)volatile 变量规则(Volatile Variable Rule):对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作,这里的「后面」同样是指时间上的先后。
这就代表了如果变量被 volatile 修饰,那么每次修改之后,其他线程在读取这个变量的时候一定能读取到该变量最新的值。
(4)线程启动规则(Thread Start Rule):Thread 对象的 start()
方法先行发生于此线程的每一个动作。
(5)线程终止规则(Thread Termination Rule):线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过 Thread 对象的 join()
方法是否结束、Thread 对象的 isAlive()
的返回值等手段检测线程是否已经终止执行。
(6)线程中断规则(Thread Interruption Rule):对线程interrupt()
方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过 Thread 对象的 interrupt()
方法检测到是否有中断发生。
(7)对象终结规则(Finalizer Rule):一个对象的初始化完成(构造函数执行结束)先行发生于它的 finalize()
方法的开始。
(8)传递性(Transitivity):如果操作 A 先行发生于操作 B,操作 B 先行发生于操作 C,那就可以得出操作 A 先行发生于操作 C 的结论。
这个很好理解,符合我们的逻辑思维。比如下面的例子:
int a = 1; // A
int b = 2; // B
int c = a + b; // C
2
3
根据程序次序规则,上述代码存在 3 个 happens-before
关系:
- A Happens-before B
- B Happens-before C
- A Happens-before C