Java 静态初始值设定项线程安全吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/878577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:33:58  来源:igfitidea点击:

Are Java static initializers thread safe?

javamultithreadingstaticsynchronizationstatic-initializer

提问by simon622

I'm using a static code block to initialize some controllers in a registry I have. My question is therefore, can I guarantee that this static code block will only absolutely be called once when the class is first loaded? I understand I cannot guarantee when this code block will be called, I'm guessing its when the Classloader first loads it. I realize I could synchronize on the class in the static code block, but my guess is this is actually what happens anyway?

我正在使用静态代码块来初始化我拥有的注册表中的一些控制器。因此,我的问题是,我能否保证在第一次加载类时,这个静态代码块只会被绝对调用一次?我知道我不能保证什么时候会调用这个代码块,我猜它是在类加载器第一次加载它的时候。我意识到我可以在静态代码块中的类上进行同步,但我猜这实际上是发生了什么?

Simple code example would be;

简单的代码示例是;

class FooRegistry {

    static {
        //this code must only ever be called once 
        addController(new FooControllerImpl());
    }

    private static void addController(IFooController controller) { 
        // ...
    }
}

or should I do this;

或者我应该这样做吗?

class FooRegistry {

    static {
        synchronized(FooRegistry.class) {
            addController(new FooControllerImpl());
        }
    }

    private static void addController(IFooController controller) {
        // ...
    }
}

采纳答案by Matthew Murdoch

Yes, Java static initializers are thread safe (use your first option).

是的,Java 静态初始值设定项是线程安全的(使用您的第一个选项)。

However, if you want to ensure that the code is executed exactly once you need to make sure that the class is only loaded by a single class-loader. Static initialization is performed once per class-loader.

但是,如果要确保代码恰好执行一次,则需要确保该类仅由单个类加载器加载。每个类加载器执行一次静态初始化。

回答by Tom Hawtin - tackline

In usual circumstances everything in the static initialiser happens-before everything that uses that class, so synchronisation is not usually necessary. However, the class is accessible to anything that the static intiailiser calls (including causing other static initialisers to be invoked).

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

A class can be loaded by a class loaded but not necessarily initialised straight away. Of course, a class can be loaded by multiples instances of class loaders and thereby become multiple classes with the same name.

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

回答by Mike Pone

Yes, Static initializers are run only once. Read this for more information.

是的,静态初始化程序只运行一次。 阅读本文了解更多信息

回答by Matt

Yes, sort of

是的,有点

A staticinitializer only gets called once, so by that definition it's thread safe -- you'd need two or more invocations of the staticinitializer to even get thread contention.

一个static初始化仅被调用一次,所以由定义,它的线程安全的-你需要在两个或两个以上的调用static初始化连得线程争。

That said, staticinitializers are confusing in many other ways. There's really no specified order in which they're called. This gets really confusing if you have two classes whose staticinitializers depend on each other. And if you use a class but don't use what the staticinitializer will set up, you're not guaranteed the class loader will invoke the static initializer.

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

Finally, keep in mind the objects you're synchronizing on. I realize this isn't really what you're asking, but make sure your question isn't really asking if you need to make addController()thread-safe.

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

回答by Peter Lawrey

This is a trick you can use for lazy initialization

这是一个可以用于延迟初始化的技巧

enum Singleton {
    INSTANCE;
}

or for pre Java 5.0

或 Java 5.0 之前的版本

class Singleton {
   static class SingletonHolder {
      static final Singleton INSTANCE = new Singleton();
   }
   public static Singleton instance() {
      return SingletonHolder.INSTANCE;
   }
}

As the static block in SingletonHolder will run once in a thread safe manner you don't need any other locking. The class SingletonHolder will only get loaded when you call instance()

由于 SingletonHolder 中的静态块将以线程安全的方式运行一次,因此您不需要任何其他锁定。类 SingletonHolder 只会在您调用 instance() 时加载

回答by ruurd

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.

所以基本上,因为你想要一个单例实例,你应该或多或少地以老式的方式来做,并确保你的单例对象被初始化一次并且只初始化一次。