【问题标题】:Java specification - example with final field [duplicate]Java规范-带有最终字段的示例[重复]
【发布时间】:2015-10-22 08:13:12
【问题描述】:

我正在阅读Java® 语言规范 Java SE 8 版17.5。 final 字段语义有一个示例 17.5-1。 Java 内存模型中的 final 字段(https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5)。

class FinalFieldExample { 
    final int x;
    int y; 
    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3; 
        y = 4; 
    } 

    static void writer() {
        f = new FinalFieldExample();
    } 

    static void reader() {
        if (f != null) {
            int i = f.x;  // guaranteed to see 3  
            int j = f.y;  // could see 0
        } 
    } 
}

描述状态:

一个线程可能执行方法编写器,另一个可能执行 方法阅读器。 因为 writer 方法在对象的构造函数之后写了 f 完成后,读者方法将保证正确看到 f.x 的初始化值:它将读取值 3。但是,f.y 是 不是最终的;因此,读者方法不能保证看到 值 4。

我用两个线程编写了一些代码来重现这种情况,但是当 reader 方法返回的不是 4 时,我无法获得案例?有构造函数总是将 f.y 设置为 4。

也许我无法理解某些事情。我会很感激澄清这一点。

编辑 谢谢大家,特别是 assyliasTesting initialization safety of final fields 完全向我解释。对我来说,这些句子是最重要的:

从 Java 5.0 开始,保证所有线程都将看到 final 构造函数设置的状态。

实际上是确保构造函数在任何之前完成 随后的程序动作发生

【问题讨论】:

  • 0 是有效结果这一事实并不意味着您的特定 JVM/OS/CPU 组合可以产生该结果。特别是我认为您无法在热点/x86 上创建这种情况。
  • 这是 Jeremy Manson 的“官方”回答:stackoverflow.com/a/15517168/829571

标签: java


【解决方案1】:

一般来说,多线程应用程序很难获得所有可能性(尤其是在涉及缓存的情况下)。甚至不可能在所有 JVM、操作系统或 CPU 上获得所有可能的结果。

假设如下: 线程 1:使用 writer 方法创建 f。 线程 2:调用 reader()。

为什么读者可以看到 f 非 null 和 f.y 与 4 不同?答案是,本地缓存可用于优化代码。比 f 已创建,但 y 的值尚未更改。

编辑: Jeremy Manson 的“官方”答案可以在here 找到。 (感谢 assylias 的评论)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-20
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 2018-03-04
    • 2012-09-21
    • 1970-01-01
    相关资源
    最近更新 更多