定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点
适用条件
当系统需要某个类只能有一个实例时适用
大致有六种写法,每一种写法各有特点:
- 懒汉 – 线程不安全
这种写法可以实现lazy-loading, 但是多个线程可能会同时申请实例,无法保证安全。 - 懒汉 – 线程安全
在1的基础上增加一个同步锁synchronized, 以保证线程安全;
但是效率不高,因为事实上只需要在第一次实例化的时候需要同步锁,以后就不可能再实例化了。 - 懒汉 – 线程安全 – 双检锁(DCL)
双检锁的奇妙之处在于,只在第一次实例化的时候才会进入第一层锁,以后就不可能进入第一次锁了;
这样多个线程进入第二层锁也只会在第一次。这就解决了第2种写法效率低下的问题。 - 懒汉 – 线程安全 – 静态内部类
这种方式能达到双检锁同样的效果,但是只在静态域延迟初始化的情况下才适用。 - 饿汉 – 线程安全
线程安全,但是不能实现lazy-loading。 - 饿汉 – 线程安全 – 枚举
最简洁的一种实现方法,不过其中的奥妙全自动需要追溯到枚举的实现上,感兴趣的读者可查阅其他资料,这里不作赘述。
自动支持序列化,但是不能实现lazy-loading。
类图
实现(java)
懒汉 – 线程不安全
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) instance = new Singleton();
return instance;
}
}
懒汉 – 线程安全
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance == null) instance = new Singleton();
return instance;
}
}
懒汉 – 线程安全 – 双检锁(DCL)
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class) {
if(instance == null) instance = new Singleton();
}
}
return instance;
}
}
懒汉 – 线程安全 – 静态内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
饿汉 – 线程安全
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
饿汉 – 线程安全 – 枚举
public enum Singleton {
INSTANCE;
public void solve() { System.out.println("ok"); }
}
实现(C#)
懒汉 – 线程不安全
class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
}
懒汉 – 线程安全
class Singleton {
private static Singleton instance = null;
private static readonly object syncRoot = new object();
private Singleton() { }
public static Singleton getInstance() {
lock (syncRoot) { //对静态只读进程辅助对象加锁
if (instance == null) instance = new Singleton();
return instance;
}
}
}
懒汉 – 线程安全 – 双检锁(DCL)
class Singleton {
private static Singleton instance = null;
private static readonly object syncRoot = new object();
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) {
lock (syncRoot) { //对静态只读进程辅助对象加锁
if (instance == null) instance = new Singleton();
}
}
return instance;
}
}
懒汉 – 线程安全 – 静态内部类
饿汉 – 线程安全
饿汉 – 线程安全 – 枚举
实现(C++)
懒汉 – 线程不安全
懒汉 – 线程安全
懒汉 – 线程安全 – 双检锁(DCL)
懒汉 – 线程安全 – 静态内部类
饿汉 – 线程安全
饿汉 – 线程安全 – 枚举
应用
不推荐使用 1 和 2
在不要求lazy-loading的情况下,推荐 5 (3 也可)
在要求lazy-loading的情况下,推荐 4 (3 也可)
涉及反序列化创建对像时,推荐 6
3 的性价比最高,万金油