问题
我正在使用静态代码块来初始化我所拥有的注册表中的某些控制器。因此,我的问题是,我可以保证这个静态代码块只在首次加载类时才会被调用一次吗?我知道我无法保证何时会调用此代码块,我猜它是在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) {
// ...
}
}
#1 热门回答(185 赞)
是的,Java静态初始化程序是线程安全的(使用你的第一个选项)。
但是,如果要确保在确保仅由单个类加载器加载类之后确实执行代码。每个类加载器执行一次静态初始化。
#2 热门回答(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类
#3 热门回答(4 赞)
在通常情况下,静态初始化器中的所有内容都会发生 - 在使用该类的所有内容之前,因此通常不需要同步。但是,静态intiailiser调用的任何内容都可以访问该类(包括调用其他静态初始化程序)。
类可以由加载的类加载,但不一定要立即初始化。当然,类可以由类加载器的多个实例加载,从而成为具有相同名称的多个类。