定义:
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。三个特点:一个类只有一个实例;必需自己创建这个实例;必需自行向整个系统提供这个实例。
结构图:
- Singleton:单例类,提供一个静态的getInstance()方法,供系统获取它的唯一实例;构造函数需要私有化;内部定义自身的一个静态变量,作为外部共享的唯一实例。
**Hungry Mode **
为了保证创建实例时的线程安全,可以使用Hungry Mode的方式初始化实例。
class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() { }
public static EagerSingleton getInstance() {
return instance;
}
}
- 在类的初始化的时候就直接创建实例,无需考虑多线程访问的问题,但无论系统是否需要改单例,都需要进行实例化。如果实例化复杂,则类加载时间较长,浪费系统资源。
Lazy Mode
为了解决初始化问题,可以在系统第一次调用的时候再生成实例。
class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() { }
synchronized public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
- 在整个getInstance()方法上面加锁可以保证线程安全,但是因为只有在第一次初始化会出现不同步的问题,如果后面所有操作都要进行加锁操作,则系统性能大幅下降。
- 如果采用双重检查锁,在一定条件下也会失效,详细参考《Java 并发编程艺术》。
Initialization Demand Holder(IoDH)
在需要实例化的单例类内引入一个静态内部类,当一次初始化实例时,由类加载器保证线程安全。既可以保证延迟加载,有可以保证线程安全,而且不影响系统性能。
//Initialization on Demand Holder
class Singleton {
private Singleton() {
}
private static class HolderClass {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return HolderClass.instance;
}
}
优点:
- 提供了对唯一实例的受控访问,用户不能实例化单例类。
- 节省系统资源,适用于一些频繁创建和销毁的对象。
缺点:
- 没有定义抽象层,很难进行扩展。
- 单例类职责过多,将单例的创建和本身功能融合在一起,一定程度上违反了“单一职责原则”。
适用场景:
- 系统只需要一个实例对象,如序列生成器,资源管理器等。
- 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。