[英]Are Java static initializers thread safe?
我正在使用静态代码块来初始化我拥有的注册表中的一些控制器。 因此,我的问题是,我能否保证在第一次加载类时,这个静态代码块只会被绝对调用一次? 我知道我不能保证什么时候会调用这个代码块,我猜它是在类加载器第一次加载它的时候。 我意识到我可以在静态代码块中的类上进行同步,但我猜这实际上是发生了什么?
简单的代码示例是;
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) {
// ...
}
}
是的,Java 静态初始值设定项是线程安全的(使用您的第一个选项)。
但是,如果要确保代码恰好执行一次,则需要确保该类仅由单个类加载器加载。 每个类加载器执行一次静态初始化。
这是一个可以用于延迟初始化的技巧
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() 时加载
在通常情况下,静态初始化程序中的所有内容都发生在使用该类的所有内容之前,因此通常不需要同步。 但是,静态初始化程序调用的任何内容都可以访问该类(包括调用其他静态初始化程序)。
一个类可以被一个加载的类加载,但不一定立即初始化。 当然,一个类可以被多个类加载器实例加载,从而成为多个同名类。
是的,有点
static
初始值设定项仅被调用一次,因此根据该定义,它是线程安全的——您甚至需要对static
初始值设定项进行两次或多次调用才能获得线程争用。
也就是说, static
初始值设定项在许多其他方面令人困惑。 调用它们确实没有特定的顺序。 如果您有两个类的static
初始值设定项相互依赖,这会变得非常混乱。 如果您使用一个类但不使用static
初始化程序将设置的内容,则不能保证类加载器将调用静态初始化程序。
最后,请记住您正在同步的对象。 我意识到这并不是您真正要问的问题,但请确保您的问题不是真正询问您是否需要使addController()
线程安全。
是的,静态初始化程序只运行一次。 阅读本文了解更多信息。
所以基本上,因为你想要一个单例实例,你应该或多或少地以老式的方式来做,并确保你的单例对象被初始化一次并且只初始化一次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.