【问题标题】:Can we treat final reorder rule in Java as happens-before rule?我们可以将 Java 中的最终重新排序规则视为发生在规则之前吗?
【发布时间】:2020-07-27 04:00:22
【问题描述】:

Java中存在两种最终记录规则,如下:

  1. a write to final field in constructorthe constructed instance reference is assigned to variable afterwards 无法重新排序
  2. read a instance referenceread the final field in the instance afterwards 无法重新排序

我们可以将上述规则视为发生之前的规则吗?

  1. a write to final field in constructor 发生在the constructed instance reference is assigned to variable afterwards
  2. read a instance reference 发生之前read the final field in the instance afterwards

我认为happens-before规则语义更强。

【问题讨论】:

  • 我认为“happens-before”较弱。 IIRC,“之前发生”仅表示线程内的“程序顺序”,加上由于同步而导致的一些线程间顺序。如果 A 发生在 B 之前,C 仍然可以观察到 B 已经发生但 A 尚未发生的不一致状态,如果 C 相对于 A 和 B 没有排序。
  • 所以我认为关键不是“更强的语义”或“更弱的语义”,这只是推导吧?感谢您的回复。 @HTNW

标签: java final happens-before


【解决方案1】:

finally在我的理解中,final关键字和happens-before规则的语义保证属于不同的范畴。以上推导是错误的,没有必要的。

【讨论】:

  • 任何错误的逻辑推导都是不必要的...... :-)
【解决方案2】:

我认为happens-before规则语义更强。

在这种情况下,最终的重新排序规则肯定更强:

  • happens-before 规则禁止在本地重新排序语句,前提是重新排序后的行为顺序一致;即仅从创建对象的线程的角度来看。

  • 相比之下,最终的重新排序规则确实明确禁止在构造函数中进行某些重新排序,除了那些会违反顺序一致性的内容。

推论:HB 不包含最终的重新排序规则。

(如果确实如此,那么根本没有必要说明后者。但是 JLS 的作者不会仅仅为了它而添加这些东西。给他们和成千上万的其他人已经阅读/研究了这些东西。)


设计目标应该是可以在任何线程中使用final 字段,而无需任何显式同步或内存模型相关的性能开销;即没有用于读取的内存屏障。

如果在构造函数中允许对 final 字段进行本地重新排序,则另一个线程将需要内存屏障以确保它看到受影响字段的一致值。我想不出一种实用的方法来优化它。在构造函数中不重新排序的潜在小影响(平均而言)小于每次读取字段的读取障碍的影响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-22
    • 1970-01-01
    • 1970-01-01
    • 2019-11-04
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 2011-09-20
    相关资源
    最近更新 更多