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

时间:2015-03-04 21:32:43

标签: java static initialization non-thread-safe

让我们有一个类定义,如

  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类的构造函数中调用,并且不是线程安全的。

上述代码是否有任何问题(除了编程风格)?考虑到类初始化的规则,假设线程安全不是问题,但程序员需要注意哪些重要事项?

2 个答案:

答案 0 :(得分:3)

正如Augusto所解释的那样,您的代码是线程安全的。但它相当令人费解。它在功能上是等效的,稍微更高效,并且更简单地做到这一点:

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

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

编辑:我也注意到该字段是公开的,而getter是私有的。这应该是另一种方式。

答案 1 :(得分:2)

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

要回答PNS对上述原始问题的评论,如果该类由2个不同的类加载器加载,则无论如何都会遇到麻烦,因为使用synchronized上的getDefaultValue()关键字会在类上创建锁定......因为你有2个班级,每个班级都是完全独立的。您可以在Java语言规范的 4.3.4参考类型相同(适用于JLS 8)一节中阅读本文。