简介
所谓单例,就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时确保只有一个对象被创建。在Java,一般常用在工具类的实现或创建对象需要消耗大量资源的场景中。
注意:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
单例模式的实现方式有很多种,各有优缺点,但是我们需要保证的基本原则是:
- 懒加载;
- 线程安全;
实现
1. 双检锁/双重校验锁(DCL,即 double-checked locking)
public class Singleton {
// 使用volatile关键字防止重排序,因为 new Instance()是一个非原子操作,可能创建一个不完整的实例
private volatile static Singleton singleton;
// 构造方法私有化,防止通过new的形式创建实例
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
// 多线程情况下保证线程安全
synchronized (Singleton.class) {
// 实现懒加载
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
2.登记式/静态内部类
描述:
这种方式利用了 classloader 机制来保证初始化 instance 时只有一个线程,Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 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;
}
}
3.枚举
描述:
这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}