Java中的线程安全单例
关于Singletons的维基百科文章提到了一些线程安全的方法来实现Java中的结构。 对于我的问题,让我们考虑具有冗长的初始化过程的单身人士,并一次由许multithreading共享。
首先,这个未提到的方法是线程安全的,如果是的话,它是同步的?
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; } }
最后,在第二个例子中,如果一个线程首先获取一个实例,另一个线程获取一个实例,并在第一个线程完成构造函数之前试图对其执行操作,那该怎么办? 那你能进入一个不安全的状态吗?
答案1: static synchronized
方法使用类对象作为锁 – 即在这种情况下Singleton.class
。
答案2:Java语言,其中包括:
- 在第一次访问/使用时加载类
- 保证在访问一个类之前,所有的静态初始化都已经完成
这两个事实意味着在调用getInstance()方法之前,不会加载内部静态类SingletonHolder
。 在那个时刻,在进行调用的线程被赋予访问之前,该类的静态实例被实例化为类加载的一部分。
这一切都意味着我们有安全的懒加载,而不需要任何同步/锁!
这种模式是用于单身人士的模式。 它击败了其他模式,因为MyClass.getInstance()
是单例的事实上的行业标准 – 每个使用它的人都会自动知道他们正在处理一个单例(使用代码,总是显而易见的),所以这个模式有正确的API 并在正确的实施之下。
顺便说一下, 比尔·普格的文章在理解单例模式时值得一读。