单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
通常单例模式在Java语言中,有两种构建方式:
- 懒汉式。指全局的单例实例在第一次被使用时构建。
- 饿汉式。指全局的单例实例在类装载时构建。
以下方式均线程安全:
懒汉式(static)
不高效,因为在任何时候只能有一个线程调用 getInstance() 方法。但是同步操作只需要在instance == null调用时才被需要,即第一次创建单例实例对象时。双重检验锁改进。
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉式(static) | 双重检验锁(double checked locking pattern)
两次检查 instance == null,一次是在同步块外,一次是在同步块内。因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例。此代码也不完美,new Singleton()并非是一个原子操作。
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null)
synchronized (Singleton.class) {
if (instance == null)
instance = new Singleton();
}
return instance;
}
}
懒汉式(static) | 静态内部类(static nested class)
推荐。
public class Singleton {
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
饿汉式(static final)
是一种懒加载模式(lazy initialization)。单例会在加载类后一开始就被初始化,即使客户端没有调用 getInstance()方法。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
枚举式(Enum)
最简单。
public enum Singleton {
INSTANCE;
}
总结
这篇博文只是自己梳理了一遍,有时间再完善完善。
参考资料
- 维基百科:单例模式
- 如何正确地写出单例模式