在构造函数运行之前,在构造函数之外初始化的最终字段是否已初始化?

时间:2018-02-07 07:53:23

标签: java multithreading thread-safety visibility safe-publication

假设您有此代码段

private final Set set = new HashSet() {{ add(1); }};


SomeConstructor() {
   printSet();
}

long printSet() {
    new Thread(() -> {System.out.println(set)}).start();
}

例如,如果编译器决定使其看起来像

private final Set set;
SomeConstructor() {
   printSet();
   set = new HashSet() {{ add(1); }};
}

这将是一个问题,因为calculateWaitTime()创建一个新的线程,可能会将该集视为null或者其中没有1。

再次提出这个问题,重新排序是否可行?或者在构造函数之外初始化的所有最终字段在构造函数之前初始化,或者至少总是由编译器移动到构造函数的顶部

1 个答案:

答案 0 :(得分:2)

final字段不可能。

请看The Java ® Language Specification Java SE 8 Edition > 17.5.2 Reading final Fields During Construction

  

17.5.2在施工期间阅读最终字段

     

读取构造该对象的线程内对象的最终字段   有关在构造函数中初始化该字段的命令   通常发生在规则之前。如果在构造函数中设置字段后发生读取,   它会看到最终字段分配的值,否则会看到默认值。

但是你也可以看到它不能保证使用反射的后续final字段修改。有关详细信息,请参阅17.5.3