从非线程安全方法初始化静态 Java 常量

Initializing a static Java constant from a non-thread-safe method

让class定义像

  public static class Bootstrapper {

    public static final Object DEFAULT_VALUE = getDefaultValue();

    private static Object getDefaultValue() {
      if (DEFAULT_VALUE == null) {
        return createValue(); // Not thread safe
      }
      return DEFAULT_VALUE;
    }
  }

其中 createValue() 方法不引用 DEFAULT_VALUE 字段,仅在 Bootstrapper class 的构造函数中以其他方式调用并且不是线程安全的。

以上代码是否有任何问题(除了编程风格)?考虑到 class 初始化的规则,大概线程安全不是问题,但是程序员需要注意什么重要的事情?

从线程的角度来看这是安全的,因为 class 加载是线程安全的,并且将在 class 之后调用该值(因此 getDefaultValue())已加载,但在它离开 class 加载代码之前。

要回答 PNS 对上述原始问题的评论,如果 class 由 2 个不同的 classloader 加载,那么无论如何你都会遇到麻烦,因为在 getDefaultValue() 将在 class... 上创建一个锁...并且由于您有 2 个 classes,每个都将完全独立。您可以在 Java 语言规范的 4.3.4 引用类型相同时(对于 JLS 8)部分阅读此内容。

正如 Augusto 所解释的,您的代码是线程安全的。但是比较绕。简单地这样做在功能上是等效的,效率稍高,也更清晰:

   public static class Bootstrapper {    
     private static final Object DEFAULT_VALUE = createValue();

     public static Object getDefaultValue() {
       return DEFAULT_VALUE;
     }
   }

编辑:我还注意到该字段是 public 而 getter 是私有的。那可能应该是相反的。