JSR-133中,有两个示例说明了大概正确同步的程序。

第一个示例由图6给出,其中:

x == y == 0

然后,线程1通过以下方式修改状态:
r1 = x;
if (r1 != 0)
y = 1;

线程2通过以下方式修改状态:
r2 = y;
if (r2 != 0)
x = 1;

作者声明该程序已正确同步,但是,该程序的执行导致生成r1 == r2 == 1。后者的值(value)怎么可能呢?

此外,图7表示为初始状态:
x == y == 0

使用线程1修改:
r1 = x;
y = r1;

和线程2执行:
r2 = y;
x = r2;

这怎么可能导致r1 == r2 == 42

最佳答案

图6 是JMM超出空中限制的示例。由于没有字段被标记为volatile,因此通常允许JVM对示例代码进行优化。这可能会导致令人惊讶的结果。

假设线程1观察到x = 1为true。现在不用担心,可能会是这种情况。在这种情况下,线程将设置y = 1。然后,后面的观察将证明对x = 1的初始观察是合理的,但是这是循环推理。如果是这样,x = y = 1将是合法的结果,并且JVM可以简单地替换两个线程中的代码以写入每个值。 JMM禁止这种形式的推理,因此x = y = 0是根据JMM唯一合法的结果。

图7 中也有类似的论点。再次,假设线程1观察x = 42。在这种情况下,线程将写入y = 42。根据这一观察,现在可以说以前的x = 42是合法的观察。但是,最初的假设是凭空做出的,因此,x = y = 0是唯一合法的结果。

事前发生关系的定义仅适用于显式同步的程序,不会禁止假设的循环推理。因此,需要严格的限制。这当然是相当学术性的,但是由于JMM是一种学术模型,因此仍然有必要定义此限制。

因此,在任一图中都没有xy可以取值的竞赛条件,即,没有竞赛条件,并且x = y = 0是唯一可能的观察结果。因此,尽管缺少volatile,但两个示例均已正确同步。

10-07 12:10