Java 静态初始化器线程安全吗?

我使用一个静态代码块来初始化一个注册表中的一些控制器。因此,我的问题是,我能否保证这个静态代码块只在类首次加载时绝对被调用一次?我知道我不能保证什么时候调用这个代码块,我猜测它是在 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) {
// ...
}
}
50847 次浏览

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

但是,如果希望确保代码只在一次执行时执行,则需要确保类只由单个类装入器装入。每个类装入器执行一次静态初始化。

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

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

是的,静态初始化器只运行一次。

算是吧

static初始化器只被调用一次,因此根据该定义,它是线程安全的——甚至需要两次或多次调用 static初始化器才能获得线程争用。

也就是说,static初始化程序在许多其他方面是令人困惑的。它们的调用没有特定的顺序。如果您有两个 static初始化器相互依赖的类,那么这会非常令人困惑。如果您使用一个类,但不使用 static初始值设置器将设置的内容,则不能保证类装入器将调用静态初始值设置器。

最后,请记住您正在同步的对象。我知道这不是你真正想问的问题,但是请确保你的问题不是真的问你是否需要使 addController()线程安全。

你可以用这个惰性初始模式

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 中的静态块将以线程安全的方式运行一次,因此不需要任何其他锁定。类 SingletonHolder 只有在调用 instance ()时才会加载

因此,基本上,既然你想要一个单例实例,你应该或多或少地用传统的方式来做,并确保你的单例对象被初始化一次,而且只有一次。