Java静态初始化程序是否安全?

sim*_*622 135 java static multithreading synchronization static-initializer

我正在使用静态代码块来初始化我所拥有的注册表中的某些控制器.因此,我的问题是,我可以保证这个静态代码块只在首次加载类时才会被调用一次吗?我知道我无法保证何时会调用此代码块,我猜它是在Classloader首次加载它时.我意识到我可以在静态代码块中同步类,但我的猜测实际上这是怎么回事?

简单的代码示例是;

class FooRegistry {

    static {
        //this code must only ever be called once 
        addController(new FooControllerImpl());
    }

    private static void addController(IFooController controller) { 
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

或者我应该这样做;

class FooRegistry {

    static {
        synchronized(FooRegistry.class) {
            addController(new FooControllerImpl());
        }
    }

    private static void addController(IFooController controller) {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*och 197

是的,Java静态初始化程序是线程安全的(使用您的第一个选项).

但是,如果要确保在确保仅由单个类加载器加载类之后,确保执行代码.每个类加载器执行一次静态初始化.

  • 啊,那我们就这么说了,所以我们说静态代码块实际上是为每个加载类的类加载器调用的.嗯......我想这应该还可以,但是,我想知道如何在OSGI环境中运行这种代码可以使用多个捆绑类加载器. (4认同)
  • @ simon622是的,但它会在每个ClassLoader中的不同类对象中运行.不同的Class对象仍具有相同的完全限定名称,但表示不能相互强制转换的不同类型. (3认同)
  • 但是,一个类可以被多个类加载器加载,因此 addController 仍然可能被多次调用(无论您是否同步调用)... (2认同)

Pet*_*rey 11

这是一个可以用于延迟初始化的技巧

enum Singleton {
    INSTANCE;
}
Run Code Online (Sandbox Code Playgroud)

或者用于Java 5.0之前的版本

class Singleton {
   static class SingletonHolder {
      static final Singleton INSTANCE = new Singleton();
   }
   public static Singleton instance() {
      return SingletonHolder.INSTANCE;
   }
}
Run Code Online (Sandbox Code Playgroud)

由于SingletonHolder中的静态块将以线程安全的方式运行一次,因此您不需要任何其他锁定.只有在调用instance()时才会加载SingletonHolder类

  • 你的答案基于这样一个事实:静态块只会在全局范围内执行一次 - 这就是被问到的问题. (18认同)
  • 我认为这在多级装载机环境中也不安全. (2认同)
  • @Ahmad多类加载器环境旨在允许每个应用程序拥有自己的单例. (2认同)