Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java final&;安全出版物_Java_Final_Safe Publication - Fatal编程技术网

Java final&;安全出版物

Java final&;安全出版物,java,final,safe-publication,Java,Final,Safe Publication,当我读到有疑问的“在新JMM下最终字段如何工作?”时,它说: 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

当我读到有疑问的“在新JMM下最终字段如何工作?”时,它说:

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;
      int j = f.y;
    }
  }
}
上面的类是如何使用final字段的示例。线程执行读取器保证看到f.x的值3,因为它是最终值。不能保证看到y的值4,因为它不是最终值

这让我感到困惑,因为writer中的代码不是安全的发布,线程执行读取器可能会看到f不是null,但是f引用的对象的构造函数尚未完成,因此即使x是final,线程执行读取器也不能保证看到f.x的值3


这是我困惑的地方,如果我错了,请纠正我,非常感谢。

这就是重点,这就是JMM中最后字段的优点。是的,编译器通常可以在对象完全构造之前为对象分配引用,这是不安全的发布,因为对象可能在部分构造状态下访问。但是,对于final字段,JMM(和编译器)保证在将引用分配给对象之前,首先准备所有final字段。发布可能仍然不安全,并且当新线程访问该对象时,该对象仍然只是部分构造,但至少最终字段将处于预期状态。从Java并发实践中的第16.3章:

初始化安全性仅保证值的可见性 在构造函数创建时,可通过最终字段访问的 完成。对于可通过非最终字段访问的值,或 施工后可能会发生变化,必须使用同步来确保 能见度


我还建议阅读第16.3章了解更多详细信息。

线程执行读取器可能会看到f不为null,但f引用的对象的构造函数尚未完成
这不可能发生,赋值发生在构造函数运行到完成之后,没有引发异常。哪种机制确保赋值发生在构造函数运行到完成之后,他说,编译器转换可以改变代码,使Helper构造函数中的代码在写入Helper变量之后发生。我认为jsr-133-faq中的代码与Jeremy Manson博客中的代码相同。