6、Java内存模型的近似模型
顺序一致性模型不适合作为java内存模型,因为它禁止了标准的编辑器和处理器优化。happens-before模型比较接近java内存模型的需求,但是它太弱了,而且它允许违反因果的事情发生。
6.1、顺序一致性模型
在顺序一致性模型中,所有的动作以全序的顺序发生,与程序顺序完全一致,每个变量的读操作都会看到写操作后的值
6.2、Happens-before模型
此模型包含几个属性/需求:
- 所有同步动作都有一个全序关系,即同步顺序。
- 同步动作包括相配对的动作间的synchronizes-with边缘
- synchronizes-with边缘的传递闭包与程序顺序产生了happens-before顺序
- 某个非volatile读操作能够看到的值由happens-before一致性规则决定
- 某个volatile读操作能看到的值由同步顺序一致性规则决定。
Happens-before 一致性说的是,在 happens-before 偏序执行轨迹中,若满足下列条件,允许对变量 v 的读操作 r 看到写操作 w 写入 v 的值:
- r 没有排在 w 前面(亦即,不是 r w 这种情况)
- 没有一个介入的对 v 的写操作 w’(亦即,不存在这样一个对 v的写操作w’:w->w’->r)。
同步顺序一致性含义是,每个对volatile变量的读操作都返回同步顺序上读操作之前最后写入的值
6.3、因果关系
happens-before内存模型描绘了一个必要而非充分的约束集。所有java内存模型允许的行为,happens-before模型也允许;但是happens-before模型允许非预期的事情发生——违反了我们建立的需求。
happens-before模型不符合要求的地方,及如何调整使其能够提供必要的保证。
6.3.1 太弱了(Too Weak)
Happens-before模型最致命的弱点是允许值凭空出现
上图中代码是正确同步的,里面没有执行任何同步动作。如果程序以顺序一致的方式执行时,没有数据争用,程序就是正确同步的。
上图代码未正确同步,可能会产生非预期的值。
顺序一致的行为:任意行为从外部来看,都与一次顺序一致性的执行结果相同
当一个写操作发生在一个其依赖的读操作之前,我们将这样的问题称为因果关系。java内存模型需要一个可以接受且一致的方式来确定哪些明显的因果循环是允许的。
6.3.2、难以捉摸的因果关系
因果关系的概念并不简单,因为不容易确定哪个动作引起了其他动作的发生。
java模型允许上图中的行为,因为编辑器可以进行如下优化:
- 消除多余的读取a的操作,将r2 = a; 替换为 r2 = r1
- 确定 r1 == r2 直接消除 第三行的if判断
- 将 b = 2提到前面执行
编辑器做优化后,b = 2一定会发生;第二次读取a总会返回与第一次一样的结果。这样,简单的编辑器优化就能导致明显的因果关系。
6.3.3、分析因果关系的途径
Java内存模型将一个特定的执行过程和一个程序作为输入,然后确定该执行过程是否是该程序的一次合法执行。