Java中的线程安全单例

don*_*ton 38 java singleton multithreading synchronization thread-safety

关于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;
    }
}
Run Code Online (Sandbox Code Playgroud)

其次,为什么以下实现线程在初始化时是安全且懒惰的?如果两个线程同时进入该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;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,在第二个示例中,如果一个线程首先获取实例而另一个线程获取实例并尝试在构造函数在第一个线程中完成之前对其执行操作,该怎么办?那你可以进入一个不安全的状态吗?

Boh*_*ian 46

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

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

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

这两个事实意味着在SingletonHolder调用getInstance()方法之前不会加载内部静态类.此时,在调用的线程被赋予访问权限之前,该类的静态实例将作为类加载的一部分进行实例化.

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

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

顺便说一句比尔Pugh的文章是值得理解的单身模式时阅读的完整性.

  • _"这种模式是用于单身人士的模式."_ - 那么[Effective Java的enum singleton](http://stackoverflow.com/questions/427902/java-enum-singleton)呢? (7认同)
  • enum singleton恕我直言不像这个那么干净或明显,因此不是那么好:`MyClass.getInstance()`是单身人士的行业标准 - 每个人自动使用它(应该)知道他们正在处理一个单身.这种模式具有正确的API*和*正确的实现方式. (3认同)
  • @donnyton - 是的,类加载器使用它自己的同步 - 想想它有点像在被加载的类上调用`static synchronized loadClass()`方法. (2认同)