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

时间:2009-05-18 16:30:29

标签: java multithreading static synchronization static-initializer

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

简单的代码示例是;

class FooRegistry {

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

    private static void addController(IFooController controller) { 
        // ...
    }
}

或者我应该这样做;

class FooRegistry {

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

    private static void addController(IFooController controller) {
        // ...
    }
}

6 个答案:

答案 0 :(得分:195)

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

但是,如果您想确保在确保该类仅由单个类加载器加载后确实执行代码。每个类加载器执行一次静态初始化。

答案 1 :(得分:11)

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

enum Singleton {
    INSTANCE;
}

或Java 5.0之前的

class Singleton {
   static class SingletonHolder {
      static final Singleton INSTANCE = new Singleton();
   }
   public static Singleton instance() {
      return SingletonHolder.INSTANCE;
   }
}

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

时才会加载SingletonHolder类

答案 2 :(得分:4)

在通常情况下,静态初始化器中的所有内容都会发生 - 在使用该类的所有内容之前,因此通常不需要同步。但是,静态intiailiser调用的任何内容都可以访问该类(包括调用其他静态初始化程序)。

类可以由加载的类加载,但不一定要立即初始化。当然,类可以由类加载器的多个实例加载,从而成为具有相同名称的多个类。

答案 3 :(得分:3)

是的,有点

static初始化程序只被调用一次,因此通过该定义它是线程安全的 - 您需要两次或多次调用static初始化程序才能获得线程争用。

尽管如此,static初始化程序在许多其他方面都令人困惑。实际上没有指定他们被调用的顺序。如果你有两个static初始值设定项彼此依赖的类,这会让人感到困惑。如果您使用类但不使用static初始化程序将设置的内容,则无法保证类加载器将调用静态初始化程序。

最后,请记住您正在同步的对象。我意识到这不是你所要求的,但要确保你的问题并不是真的在问你是否需要让addController()线程安全。

答案 4 :(得分:0)

是的,静态初始值设定项只运行一次。 Read this for more information

答案 5 :(得分:-3)

So basically, since you want a singleton instance, you should do it more or less the old-fashioned way and make sure your singleton object is initialised once and only once.