【问题标题】:Synchronized reordering in javajava中的同步重排序
【发布时间】:2019-03-19 06:54:05
【问题描述】:

众所周知,JVM 不应该将语句从同步块重新排序到同步块之外。考虑到这一点,是否允许 JVM 重新排序分配 y = 7 以发生在以下 sn-p 中的 synchronized 块之后?

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

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

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

有人可能会争辩说,因为这是一个有效的排序,y 分配不能发生在 synchronized 块之后,因为它违反了来自同步块中的代码不得重新排序以发生在块之后的规则,并且推断出同步块的y happens-before end

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

综上所述,next ordering是第一个sn-p的有效排序吗?

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

【问题讨论】:

  • 在互联网上漫游后,我很确定我在这里的推理是有缺陷的
  • 当前形式的代码 sn-ps 看起来像 xy 是方法局部变量,即使您可能的意思是它们是多个线程可以访问的非私有字段?
  • 是的,我不知道,我已经修复了示例

标签: java synchronized


【解决方案1】:

JLS 17.4.5:

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

...

  • 如果动作 x 与后续动作 y 同步,那么我们也有 hb(x, y)。

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

【讨论】:

  • 是的,但这是针对单个线程的;据我了解,OP 真的意味着y 是共享的
  • @Eugene 这就是我所说的“假设”。第二个要点是将这个线程链接到其他线程。
  • @chrylis 对,在这种情况下,由于 OP 确认刚刚共享了 y,您可能需要更新您的答案以准确反映这一点。
【解决方案2】:

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

监视器输入就像volatile load(不完全正确,但我理解它更简单 - 将插入两个障碍:LoadLoad|LoadStore)和 before 的操作可以不要飘过那道屏障。

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

【讨论】:

  • 您确实看到了这与我之前的问题 (stackoverflow.com/questions/52805020/…) 的链接方式吗?目前的共识是第三次读取可以发生在同步块之前,尽管它在某种意义上有所不同,如果同步块被执行,它取决于第一次读取
  • 我认为我不能同时接受这两个答案。
  • 抱歉,你误解了我的意思,我指的是@chrylis 对这个问题的回答和对我其他问题的 Kineolyan 回答。我不认为他们两个都是正确的。我确实都赞成
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-01
  • 2011-03-11
  • 2016-03-04
  • 1970-01-01
  • 2015-07-25
相关资源
最近更新 更多