Java中的线程安全单例

时间:2011-08-13 02:38:15

标签: java multithreading synchronization thread-safety singleton

关于Singletons的维基百科文章提到了一些在Java中实现结构的线程安全方法。对于我的问题,让我们考虑具有冗长初始化过程并且同时被许多线程所接受的单身人士。

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

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 个答案:

答案 0 :(得分:46)

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

答案2:java语言,其中包括:

  • 首次访问/使用时加载类
  • 保证在允许访问类之前,所有静态初始化程序都已完成

这两个事实意味着在调用getInstance()方法之前不会加载内部静态类SingletonHolder。在那一刻,在调用的线程被赋予对它的访问权限之前,该类的静态实例被实例化为类加载的一部分。

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

此模式是用于单身人士的 模式。它击败了其他模式,因为MyClass.getInstance()是单身人士的事实行业标准 - 每个使用它的人都会自动知道他们正在处理单身人士(使用代码,显然总是很好),因此这种模式具有正确的API 正确的实施方式。

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