java 单例模式(Bill Pugh 的解决方案)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6109896/
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
Singleton pattern (Bill Pugh's solution)
提问by Rob Fox
I'm reading wiki about the singleton pattern and I'm not sure if I understand this: https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiompart of it correctly.
我正在阅读有关单例模式的 wiki,我不确定我是否理解这一点:https: //en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom部分正确。
So to make it simple: Why is Bill Pugh's solution better than the example above?
简单来说:为什么 Bill Pugh 的解决方案比上面的示例更好?
Is it because a static class is not load by the VM before it's actually used or something like this, so we don't create the object before we turn to the getInstance() method? Also is that method thread safe only to the extent of initializing the object?
是不是因为静态类在实际使用之前没有被虚拟机加载或类似的东西,所以我们在转向 getInstance() 方法之前不创建对象?该方法线程是否仅在初始化对象的范围内安全?
采纳答案by planetjones
I think Mr Pugh's version is held in high regard because it only performs the instantiation of the singleton when getInstance()
is called i.e. not when the class (the class holding the getInstance method) is loaded. If your singleton construction does something costlythen this may be an advantage for you. If you're like the majority of the world whose singletons are just to avoid static methods (and you haven't moved onto dependency injection frameworks), then I would not lose any sleep over it.
我认为 Pugh 先生的版本受到高度重视,因为它只在getInstance()
被调用时执行单例的实例化,即在加载类(持有 getInstance 方法的类)时不执行。如果你的单例结构做了一些昂贵的事情,那么这对你来说可能是一个优势。如果您像世界上大多数人一样,单例只是为了避免静态方法(并且您还没有转向依赖注入框架),那么我不会为此失眠。
As the article states, Mr Pugh's method is lazier than the static instance variable - but in reality if the Singleton class gets loaded you're going to be calling the getInstance method anyhow. So as a computer science exercise it's useful, but in the real world its benefits are debatable.
正如文章所述,Pugh 先生的方法比静态实例变量更懒惰——但实际上,如果加载了 Singleton 类,您无论如何都会调用 getInstance 方法。因此,作为计算机科学练习,它很有用,但在现实世界中,它的好处值得商榷。
p.s. I don't care much for Mr Bloch's example here as to use an enum would be to say My Singleton IS-A enum, which doesn't sound right to me (especially from someone who, rightly, says never implement an interface just to get the constants)
ps 我不太在意布洛赫先生在这里的例子,因为使用枚举会说我的单例是一个枚举,这对我来说听起来不合适(尤其是对于那些说永远不会实现接口的人来说只是得到常数)
回答by JB Nizet
The JLS guarantees that a class is only loaded when it's used for the first time (making the singleton initialization lazy), and that the class loadingis thread-safe (making the getInstance()
method thread-safe as well)
JLS 保证类只在第一次使用时加载(使单例初始化延迟),并且类加载是线程安全的(使getInstance()
方法也是线程安全的)
As for why thread-safe
至于为什么线程安全
Because the first time getInstance() is called, the JVM will hold the holder class. If another thread calls getInstance() concurrently, the JVM won't load the holder class a second time: it will wait for the first thread to have completed the class loading, and at the end of the loading and initialization of the holder class, both thread will see the holder class properly initialized and thus containing the unique singleton instance.
因为第一次调用 getInstance() 时,JVM 将持有持有者类。如果另一个线程并发调用getInstance(),JVM不会第二次加载holder类:它会等待第一个线程完成类加载,在holder类的加载和初始化结束时,两个线程都会看到持有者类正确初始化,从而包含唯一的单例实例。
回答by Sean Patrick Floyd
Is it because a static class is not load by the VM before it's actually used
是不是因为静态类在实际使用之前没有被虚拟机加载
Not just a static class, any class. Classes aren't loaded until they are referenced. See the JLS - 12.4.1 When Initialization Occurs
不只是一个静态类,任何类。类在被引用之前不会被加载。请参阅 JLS - 12.4.1 初始化发生时
or something like this, so we don't create the object before we turn to the getInstance() method?
或类似的东西,所以我们在转向 getInstance() 方法之前不创建对象?
Exactly.
确切地。
Also is that method thread safe only to the extent of initializing the object?
该方法线程是否仅在初始化对象的范围内安全?
Handing out a reference is thread-safe, so this method is always thread-safe, not just at creation time
分发引用是线程安全的,因此该方法始终是线程安全的,而不仅仅是在创建时
回答by khachik
The key part of the explanation is the following:
解释的关键部分如下:
The nested class is referenced no earlier (and therefore loaded no earlier by the class loader) than the moment that getInstance() is called. Thus, this solution is thread-safe without requiring special language constructs (i.e. volatile or synchronized).
嵌套类不会早于调用 getInstance() 的那一刻被引用(因此类加载器不会早于加载)。因此,该解决方案是线程安全的,不需要特殊的语言结构(即 volatile 或 synchronized)。
Bill Pogh's solution provides laziness.
Bill Pogh 的解决方案提供了惰性。
回答by Michael Borgwardt
Is it because a static class is not load by the VM before it's actually used or something like this, so we don't create the object before we turn to the getInstance() method?
是不是因为静态类在实际使用之前没有被虚拟机加载或类似的东西,所以我们在转向 getInstance() 方法之前不创建对象?
Correct.
正确的。
Also is that method thread safe only to the extent of initializing the object?
该方法线程是否仅在初始化对象的范围内安全?
It ensures that only one instance is created and no client receives anything but a reference to that fully initialized instances.
它确保只创建一个实例,并且除了对完全初始化的实例的引用之外,没有客户端接收任何内容。