2015-10-12 48 views
1

我越来越困惑应该使用哪一个来创建一个同步的单例类对象。我知道以下两种实现方式。如何使Java对象同步?哪个更好,为什么?

static volatile PaymentSettings paymentSettings = null; 

public static PaymentSettings getInstance() { 
    if (paymentSettings == null) { 
     synchronized (PaymentSettings.class) { 
      if (paymentSettings == null) 
       paymentSettings = new PaymentSettings(); 
     } 
    } 
    return paymentSettings; 
} 

而且

private static class PaymentSettingsInstanceHolder { 
    private static PaymentSettings instance = new PaymentSettings(); 
} 

public static PaymentSettings getInstance() { 
    return PaymentSettingsInstanceHolder.instance; 
} 

请建议我应该使用哪种方法,为什么?

+2

这不会使对象同步。我不确定我甚至知道这意味着什么。这会创建一个懒惰的初始化单例!第二种方法好得多。 –

+1

通过'synchronized(PaymentSettings.class)'同步可能导致死锁(很少,但可能),因为锁可从外部获得(也就是说,如果调用者也在该锁上同步)。如果你喜欢做同步化的惰性init,你可以使用Apache commons中的LazyInitializer。 https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/concurrent/LazyInitializer.html - 除此之外:这两种方法在施工时间不同(懒惰与非懒惰),而不是他们如何做同步 - 哪一个更好取决于其他方面。 –

+0

更好总是取决于你想达到的目标。你没有在你的问题中陈述这些问题 –

回答

1

这两种机制是实现Singleton的常见尝试。

第一个被称为Double-checked locking并且通常被认为是中断的,尽管您对该类的锁定技术可能是可接受的解决方法。

你的第二个是一个整洁的解决方案,但可能会在不需要时创建对象。

现在认为最好的解决方案是使用enum。这确保该对象仅在需要时而不是在之前创建。请参阅here,了解为什么这很好。

final class Singleton { 

    private Singleton() { 
     // Make sure only I can create one. 
    } 

    private enum Single { 

     INSTANCE; 
     // The only instance - ever. 
     final Singleton s = new Singleton(); 

    } 

    public static Singleton getInstance() { 
     // Will force the construction here only. 
     return Single.INSTANCE.s; 
    } 
} 
+1

我想大多数情况是这样匹配OP的原始签名作为public enum PaymentSettings {INSTANCE;他们真的需要。或者他们是这种方式的其他原因? – weston

+0

@weston - 是的,还有更多。 'enum'确保在最后一分钟只有一次施工。它还提供了开箱即用的序列化。此外,“私人单身人士......”的存在保证**的合同只能有一个**。另外,你不应该暴露'enum'本身,你应该让'enum'实例化单例。 – OldCurmudgeon

+0

我知道为什么枚举,我问你有什么更长的路,克服了我张贴的更短的方式(并链接到)。它隐藏了枚举,但为什么更好?如果你按自己的方式去做,你也应该有'final'类。 – weston