2011-08-13 35 views
36

关于Singletons的维基百科文章提到了几种线程安全的方式来实现Java中的结构。对于我的问题,让我们考虑具有冗长的初始化过程并且一次被许多线程共享的单例。Java中的线程安全Singletons

首先,这是未提及的方法线程安全的,如果是的话,它在什么同步?

public class Singleton { 
    private Singleton instance; 

    private Singleton() { 
     //lots of initialization code 
    } 

    public static synchronized Singleton getInstance() { 
     if(instance == null) { 
      instance = new Singleton(); 
     } 
     return instance; 
    } 
} 

其次,为什么下面的实现线程安全和懒惰的初始化?如果两个线程同时输入getInstance()方法,会发生什么情况?

public class Singleton { 
    private Singleton() { 
     //lots of initialization code 
    } 

    private static class SingletonHolder { 
     public static final Singleton instance = new Singleton(); 
    } 

    public static Singleton getInstance() { 
     return SingletonHolder.instance; 
    } 
} 

最后,在第二个例子,如果一个线程首先获得一个实例,而另一个线程获取一个实例,并试图构造函数中的第一个线程完成之前执行它的动作?那么你会进入一个不安全的状态吗?

回答

44

答案1:static synchronized方法使用类对象作为锁 - 即在这种情况下Singleton.class

答2:Java语言中,除其他事项外:

  • 加载类时首先访问他们/使用
  • 保证被允许访问上课前,所有静态初始化完成

这两个事实意味着内部静态类SingletonHolder直到getInstance()方法被调用才加载。在那个时刻,在进行调用的线程被授予访问权限之前,该类的静态实例被实例化为类加载的一部分。

这一切都意味着我们有安全延迟加载,没有任何需要同步/锁!

这种模式是模式用于单身人士。它击败了其他模式,因为MyClass.getInstance()是单件的事实上的行业标准 - 每个使用它的人都会自动知道他们正在处理一个单例(使用代码,它总是显而易见),所以此模式具有合适的API 在引擎盖下正确实施。

btw Bill Pugh's article在理解单例模式时值得一读。

+0

阅读完这篇文章后,我是否正确地说Java在加载静态字段时会进行一些“内部”同步? – donnyton

+7

_“这种模式是用于单例模式。”_ - 以及[有效的Java的枚举单例](http://stackoverflow.com/questions/427902/java-enum-singleton)? –

+3

枚举单例的恕我直言不像这个那样干净明显,因此也不是那么好:'MyClass.getInstance()'是单身人士的行业标准 - 每个人自动使用它(应该)知道他们正在处理一个单身。这种模式有正确的API *和*引擎盖下的正确实施。 – Bohemian