Aiur

zellux 的博客

Singleton 模式与双检测锁定(DCL)

看 OOP 教材时,书里提到了一个双检测锁定(Double-Checked Lock, DCL)的问题,但是没有更多介绍,只是说这是一个和底层内存机制有关的漏洞。查阅了下相关资料,对这个问题大致有了点了解。 从头开始说吧。 在多线程的情况下Singleton模式会遇到不少问题,一个简单的例子 class Singleton { private static Singleton instance = null; public static Singleton instance() { if (instance == null) { instance = new Singleton(); } return instance; } } 假设这样一个场景,有两个线程调用 Singleton.instance(),首先线程一判断 instance 是否等于 null,判断完后一瞬间虚拟机把线程二调度为运行线程,线程二再次判断 instance 是否为 null,然后创建一个Singleton 实例,线程二的时间片用完后,线程一被唤醒,接下来它依然会创建一个新的 Singleton 实例,导致两次调用范围的对象不同。 最简单的方法自然是在类被载入时就初始化这个对象: private static Singleton instance = new Singleton(); JLS (Java Language Specification) 中规定了一个类只会被初始化一次,所以这样做肯定是没问题的。 但是如果要实现延迟初始化(Lazy initialization),比如这个实例初始化时的参数要在运行期才能确定,应该怎么做呢? 依然有最简单的方法:使用 synchronized 关键字修饰初始化方法: public synchronized static Singleton instance() { if (instance == null) { instance = new Singleton(); } return instance; } 然而引入 synchronized 关键字后,产生了一个性能问题:多个线程同时访问这个方法时,会因为同步原语而导致每次只有一个线程执行这段代码,影响程序性能。而事实上初始化完毕后只需要简单的返回 instance 的引用就行了。 阅读全文 →