Java 单例模式(Bill Pugh和#x27;的解决方案)
我正在读关于singleton模式的维基,我不确定我是否理解了这一点:部分理解是正确的 简单来说:为什么Bill Pugh的解决方案比上面的例子更好? 这是因为一个静态类在实际使用之前或者类似的情况下并没有被VM加载,所以我们在使用getInstance()方法之前不创建对象吗?Java 单例模式(Bill Pugh和#x27;的解决方案),java,design-patterns,singleton,Java,Design Patterns,Singleton,我正在读关于singleton模式的维基,我不确定我是否理解了这一点:部分理解是正确的 简单来说:为什么Bill Pugh的解决方案比上面的例子更好? 这是因为一个静态类在实际使用之前或者类似的情况下并没有被VM加载,所以我们在使用getInstance()方法之前不创建对象吗? 另外,该方法仅在初始化对象时才是线程安全的吗?我认为Pugh先生的版本受到高度重视,因为它只在调用getInstance()时执行单例的实例化,即在加载类(持有getInstance方法的类)时不执行。如果你的单例构造
另外,该方法仅在初始化对象时才是线程安全的吗?我认为Pugh先生的版本受到高度重视,因为它只在调用
getInstance()
时执行单例的实例化,即在加载类(持有getInstance方法的类)时不执行。如果你的单例构造做了一些花费不菲的事情,那么这对你来说可能是一个优势。如果你像世界上大多数人一样,他们的单例只是为了避免静态方法(而且你还没有进入依赖注入框架),那么我不会为此而失眠
正如文章所述,Pugh先生的方法比静态实例变量更慢——但实际上,如果Singleton类被加载,那么无论如何都将调用getInstance方法。因此,作为一个计算机科学练习,它是有用的,但在现实世界中,它的好处是有争议的
p、 我不太喜欢布洛赫先生的例子,因为使用枚举就是说我的单例是一个枚举,这对我来说不太合适(特别是有人说,正确的话,他说永远不要实现接口只是为了得到常量)JLS保证类只有在第一次使用时才被加载(使单例初始化延迟),并且类加载是线程安全的(使
getInstance()
方法也是线程安全的)
至于为什么线程安全
因为第一次调用getInstance(),JVM将持有holder类同时,JVM不会第二次加载holder类:它将等待第一个线程完成类加载,在holder类的加载和初始化结束时,两个线程都会看到holder类正确初始化,从而包含唯一的单实例 是不是因为静态类不是 在虚拟机实际运行之前由虚拟机加载 用过或类似的东西,所以我们 在我们转向之前不要创建对象 到getInstance()方法 对 另外,该方法仅在初始化对象时才是线程安全的吗 它确保只创建一个实例,并且客户端只接收对完全初始化的实例的引用 是不是因为静态类不是 在虚拟机实际运行之前由虚拟机加载 使用 不只是一个静态类,任何类。在引用类之前不会加载它们。请参阅JLS- 或者类似的事情,所以我们不 在我们转向之前创建对象 getInstance()方法 没错 同样,该方法仅是线程安全的吗 在初始化 反对
分发引用是线程安全的,因此此方法始终是线程安全的,而不仅仅是在创建时。解释的关键部分如下所示: 嵌套类没有被引用 之前(因此加载了 由类加载器执行)比 调用getInstance()的时刻。 因此,此解决方案是线程安全的 不需要特殊语言 构造(即易失性或 已同步)
Bill Pogh的解决方案提供了惰性。但是如果我的类除了singleton之外没有其他方法,那么它就不会在getInstance()之前被实例化是否仍被调用?Pugh先生示例中的静态类只有在调用getInstance时才会被加载,因为这是它第一次被引用。持有getInstance方法的公共类可能只有getInstance方法-因此,正如我上面从计算机科学的角度所说,这很有趣,但实际上它与对“传统简单方式”的背离我之所以选择enum的思维方式,是因为该类的实例数量是静态已知的。这就像西服的类示例,其中正好有四个;这里我们有一个enum,其中正好有一个成员,
INSTANCE
。尽管我能理解这样的观点,即这是令人困惑的。(然而“奇怪”这个静态定义的单一实例实际上只是强调了单一模式的弱点。对于一个关于“双顿”的枚举,enum DatabaseConnection{LIVE,TEST}
?)@Andrzej Doyle我认为你的观点是有道理的。我想我看到当枚举值中有某种意义时使用枚举,也就是说,它具有函数意义,并且你只希望在系统中使用该值的单个表示形式。我见过CustomerLogic或AccountLogic等类作为单例实现(只是为了避免使用静态方法),在这种情况下,我看不到枚举是逻辑上合适的,即使从技术上讲它适合作业。@实际上,持有getInstance()方法的公共类通常至少有一个实例方法(例如java.awt.Toolkit)——重要的一点是getInstance()首先调用。嗨,我实际上不明白它是如何线程安全的。你能解释一下吗?因为第一次调用getInstance()时,JVM将持有holder类。如果另一个线程调用getInstance()同时,JVM不会第二次加载holder类:它将等待第一个线程完成类加载,在holder类的加载和初始化结束时,两个线程都会看到holder类正确初始化,从而包含唯一的单实例。