我正在使用静态代码块来初始化我所拥有的注册表中的某些控制器。因此,我的问题是,我可以保证这个静态代码块只在首次加载类时才会被调用一次吗?我知道我无法保证何时会调用此代码块,我猜它是在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) {
// ...
}
}
答案 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.