我正在阅读关于单身人士模式的维基,我不确定我是否理解这一点:https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom部分内容是正确的。
为了简单起见:为什么Bill Pugh的解决方案比上面的例子更好?
是因为VM在实际使用之前没有加载静态类或类似的东西,所以在转向getInstance()方法之前我们不创建对象? 那个方法线程安全只是在初始化对象的程度吗?
答案 0 :(得分:29)
我认为Pugh先生的版本受到高度重视,因为它仅在调用getInstance()
时执行单例的实例化,即不在加载类(包含getInstance方法的类)时执行。如果你的单身人士建筑做了昂贵的,那么这对你来说可能是一个优势。如果你像世界上大多数人一样,他们的单身人士只是为了避免使用静态方法(并且你没有转向依赖注入框架),那么我就不会失去任何睡眠。
正如文章所述,Pugh先生的方法比静态实例变量更懒惰 - 但实际上如果Singleton类被加载,你无论如何都会调用getInstance方法。因此,作为计算机科学的一部分,它很有用,但在现实世界中它的好处值得商榷。
P.S。我不太关心布洛赫先生在这里的例子,因为使用枚举就是说我的单身人士IS-A枚举,这对我来说听起来并不合适(尤其是那些正确地说,从来没有实现过接口的人得到常数)
答案 1 :(得分:20)
JLS保证只在第一次使用它时才加载一个类(使单例初始化变得懒惰),并且类加载是线程安全的(使{{1}方法也是线程安全的)
至于线程安全的原因
因为第一次调用getInstance(),JVM将持有holder类。如果另一个线程同时调用getInstance(),JVM将不会再次加载holder类:它将等待第一个线程完成类加载,并在加载和初始化holder类时,两个线程都会看到holder类正确初始化,因此包含唯一的单例实例。
答案 2 :(得分:7)
是因为静态类不是 虚拟机在实际加载之前加载 使用
不仅仅是静态类,任何类。在引用类之前不会加载类。请参阅JLS - 12.4.1 When Initialization Occurs
或类似的东西,所以我们没有 在我们转向之前创建对象 getInstance()方法?
完全。
也是该方法线程安全 到初始化的程度 对象
发布引用是线程安全的,因此该方法始终是线程安全的,而不仅仅是在创建时
答案 3 :(得分:1)
是因为静态类不是 虚拟机在实际加载之前加载 使用或类似的东西,所以我们 我们转之前不要创建对象 到getInstance()方法?
正确。
该方法的线程安全性仅在初始化对象的范围内吗?
它确保只创建一个实例,并且除了对完全初始化的实例的引用外,没有客户端接收任何内容。
答案 4 :(得分:1)
解释的关键部分如下:
嵌套类引用为no 早些时候(因此加载没有 早于类加载器)比 调用getInstance()的时刻。 因此,该解决方案是线程安全的 不需要特殊语言 构造(即挥发性或 同步)。
Bill Pogh的解决方案提供了懒惰。