单例模式(Bill Pugh 的解决方案)

发布于 2024-11-09 13:17:17 字数 374 浏览 0 评论 0原文

我正在阅读关于单例模式的维基,我不确定我是否理解这一点: https ://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom 部分内容正确。

所以简单来说:为什么 Bill Pugh 的解决方案比上面的例子更好?

是因为静态类在实际使用之前没有被 VM 加载还是类似的原因,所以我们不这样做在我们转向 getInstance() 方法之前创建对象? 另外,该方法仅在初始化对象的范围内是线程安全的吗?

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_idiom part of it correctly.

So to make it simple: Why is Bill Pugh's solution better than the example above?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

孤单情人 2024-11-16 13:17:17

我认为 Pugh 先生的版本受到高度重视,因为它仅在调用 getInstance() 时执行单例实例化,即在加载类(持有 getInstance 方法的类)时不执行单例实例化。如果您的单例构造做了一些成本高昂的事情,那么这对您来说可能是一个优势。如果您像世界上大多数人一样,其单例只是为了避免静态方法(并且您还没有转向依赖注入框架),那么我不会为此失眠。

正如文章所述,Pugh 先生的方法比静态实例变量更惰性 - 但实际上,如果加载 Singleton 类,无论如何您都会调用 getInstance 方法。因此,作为一项计算机科学练习,它是有用的,但在现实世界中,它的好处是有争议的。

ps 我不太关心 Bloch 先生在这里的例子,因为使用枚举就是说 My Singleton IS-A 枚举,这对我来说听起来不太正确(特别是来自那些正确地说永远不要实现接口的人)获取常数)

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 costly then 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.

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.

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)

套路撩心 2024-11-16 13:17:17

JLS 保证类仅在第一次使用时才加载(使得单例初始化变得懒惰),并且类加载是线程安全的(使得 getInstance()< /code> 方法也是线程安全的)

至于为什么线程安全

因为第一次调用 getInstance() 时,JVM 会加载holder类。如果另一个线程同时调用 getInstance(),JVM 不会第二次加载 Holder 类:它会等待第一个线程完成类加载,并在 Holder 类加载和初始化结束时,两个线程都会看到持有者类已正确初始化,因此包含唯一的单例实例。

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 loading is thread-safe (making the getInstance() method thread-safe as well)

As for why thread-safe

Because the first time getInstance() is called, the JVM will load 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.

£烟消云散 2024-11-16 13:17:17

是不是因为静态类不是
在实际运行之前由虚拟机加载
使用过

不只是静态类,任何类。类在被引用之前不会被加载。请参阅 JLS - 12.4.1 何时发生初始化

或者类似的东西,所以我们不
在我们转向之前创建对象
getInstance() 方法?

确切地。

该方法仅是线程安全的
到初始化的程度
对象?

分发引用是线程安全的,因此该方法始终是线程安全的,而不仅仅是在创建时

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

or something like this, so we don't
create the object before we turn to
the getInstance() method?

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

救星 2024-11-16 13:17:17

解释的关键部分如下:

嵌套类没有被引用
更早(因此没有加载
早于类加载器)
调用 getInstance() 的那一刻。
因此,这个解决方案是线程安全的
无需特殊语言
构造(即易失性或
同步)。

Bill Pogh 的解决方案提供了惰性。

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).

Bill Pogh's solution provides laziness.

南街九尾狐 2024-11-16 13:17:17

是不是因为静态类不是
在实际运行之前由虚拟机加载
用过或类似的东西,所以我们
在我们转向之前不要创建对象
到 getInstance() 方法?

正确的。

该方法仅在初始化对象的范围内是线程安全的吗?

它确保只创建一个实例,并且除了对该完全初始化的实例的引用之外,任何客户端都不会收到任何内容。

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?

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.

萌化 2024-11-16 13:17:17

静态内部类将包含 Singleton 实例。当静态内部类加载到内存中时,它将创建 Singleton 实例。它不需要同步。

公共类单例{

private Singleton (){}

private static class SingletonHelper{
    private static final Singleton INSTANCE = new Singleton ();
}

public static Singleton getInstance(){
    return SingletonHelper.INSTANCE;
}

}

Static inner class will contain the Singleton instance. It will create the Singleton instance when the static inner class is loaded into the memory. It doesn't require synchronization.

public class Singleton {

private Singleton (){}

private static class SingletonHelper{
    private static final Singleton INSTANCE = new Singleton ();
}

public static Singleton getInstance(){
    return SingletonHelper.INSTANCE;
}

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文