繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM