Java 中的同步重新排序



众所周知,JVM不应该将语句从同步块内重新排序到同步块外部。考虑到这一点,是否允许 JVM 对以下代码片段中synchronized块之后发生的分配y = 7进行重新排序?

x = 5;
y = 7;
synchronized (this) {
x = 6;
}

我们知道,同步块之前的变量赋值可以重新排序以在块内发生。因此,以下内容应该是初始代码的有效重新排序:

x = 5;
synchronized (this) {
x = 6;
y = 7;
}

有人可能会争辩说,因为这是一个有效的排序,所以y分配不能在synchronized块之后发生,因为它违反了以下规则:同步块中的代码不得重新排序以在块之后发生,并推断y在同步块结束之前发生

另一方面,可能是所有排序都不等效,哪个排序是实际排序很重要。具体来说,如果y分配最初是在同步块内完成的,则在块之后不会发生,否则可能会发生。

综上所述,下一个排序对第一个代码段的排序是否有效?

x = 5;
synchronized (this) {
x = 6;
}
y = 7;

JLS 17.4.5:

  • 如果 x 和 y 是同一线程的操作,并且 x 在程序顺序中位于 y 之前,则 hb(x, y(。

  • 如果一个动作 x 与下一个动作 y 同步,那么我们也有 hb(x, y(。

只有当包含y的值可能在当前线程之外可见的假设时,您的问题才有意义。如果是这种情况,这两个规则的组合要求在同步块之后不要对赋值进行重新排序。

是的,你的推理是有缺陷的;这不可能发生。

监视器输入就像一个volatile load(不完全正确,但我理解得更简单 - 将插入两个障碍:LoadLoad|LoadStore(,并且之前的操作不能漂浮在该障碍上。

我很确定,这是由JLS指定的,虽然我想链接到它,但另一个答案已经做到了 - 去投票吧。

最新更新