在Java Concurrency In Practice一书中,我们被告知可以通过编译器,JVM在运行时甚至由处理器重新排序程序的指令。因此,我们应该假设执行的程序的执行顺序与我们在源代码中指定的顺序完全相同。
然而,讨论Java内存模型的最后一章提供了发生在之前规则的列表,指出了JVM保留哪些指令排序。第一条规则是:
我认为“程序顺序”是指源代码。
我的问题:假设这条规则,我想知道哪些指令可能实际重新排序。
“行动”定义如下:
Java内存模型是根据操作指定的,包括对变量的读写,监视器的锁定和解锁,以及启动和连接线程。 JMM定义了在程序中的所有操作之前调用的部分排序。为了保证执行动作B的线程可以看到动作A的结果(A和B是否出现在不同的线程中),必须在A和B之间的关系之前发生。在没有发生之前在两个之间进行排序操作,JVM可以随意重新排序。
提到的其他订单规则是:
答案 0 :(得分:54)
程序订单规则的关键点是: 在一个帖子中 。
想象一下这个简单的程序(所有变量最初为0):
T1:
x = 5;
y = 6;
T2:
if (y == 6) System.out.println(x);
从T1的角度来看,执行必须与在x(程序顺序)之后分配的y一致。但是从T2的角度来看,并非如此,T2可能会打印0。
实际上允许T1首先分配y,因为2个分配是独立的,交换它们不会影响T1的执行。
通过适当的同步,T2将始终打印5或不打印。
修改强>
你似乎误解了程序顺序的含义。 The program order rule boils down to:
如果
x
和y
是同一个帖子的操作,并且x
按照程序顺序排在y
之前,那么hb(x, y)
(即x
} 发生在y
之前。
发生 - 之前在JMM中具有非常特殊的含义。特别是,从挂钟的角度来看,不意味着y=6
必须在T1 x=5
之后。它只表示T1执行的操作序列必须与该命令一致。您也可以参考JLS 17.4.5:
应该注意的是,两个行为之间存在先发生关系并不一定意味着它们必须在实施中以该顺序发生。如果重新排序产生的结果与合法执行一致,则不是非法的。
在上面给出的示例中,您将同意从T1的角度(即在单线程程序中),x=5;y=6;
与y=6;x=5;
一致,因为您没有读取值。在T1中,保证下一行的声明,以查看这两个动作,无论它们的执行顺序如何。