单例模式(Singleton Pattern)
目的:确保一个类只有一个实例,并提供一个全局访问点。
关键点
- 唯一实例:保证一个类只有一个实例。
- 全局访问点:提供访问该实例的全局访问点。
优点
- 控制实例数量:确保内存中只有一个实例,节省系统资源。
- 全局访问:提供一个全局访问点,方便实例的访问和管理。
缺点
- 单一职责原则:可能会违反单一职责原则,因为类不仅管理实例的创建,还要管理自己的生命周期。
- 测试困难:难以对其进行单元测试,因为它的状态是全局的。
实现方式
有多种方式来实现单例模式,例如懒汉式、饿汉式、双重检查锁等。我们将通过以下几种方式实现单例模式。
一、代码实现
饿汉式(Eager Initialization)
饿汉式在类加载时就实例化单例对象,线程安全。
public class Singleton {
// 静态初始化单例实例
private static final Singleton instance = new Singleton();
// 私有构造函数,防止外部实例化
private Singleton() {}
// 提供全局访问点
public static Singleton getInstance() {
return instance;
}
}
懒汉式(Lazy Initialization)
懒汉式在第一次调用 getInstance
时才创建实例,但线程不安全。
public class Singleton {
// 单例实例,延迟初始化
private static Singleton instance;
// 私有构造函数,防止外部实例化
private Singleton() {}
// 提供全局访问点
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
线程安全的懒汉式(Thread-safe Lazy Initialization)
使用 synchronized
关键字保证线程安全,但性能较低。
public class Singleton {
// 单例实例,延迟初始化
private static Singleton instance;
// 私有构造函数,防止外部实例化
private Singleton() {}
// 提供全局访问点
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
双重检查锁(Double-checked Locking)
通过减少 synchronized
的使用,提升性能。
public class Singleton {
// 使用 volatile 确保可见性
private static volatile Singleton instance;
// 私有构造函数,防止外部实例化
private Singleton() {}
// 提供全局访问点
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类(Static Inner Class)
利用类加载机制确保线程安全,推荐使用。
public class Singleton {
// 私有构造函数,防止外部实例化
private Singleton() {}
// 静态内部类,延迟加载单例实例
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
// 提供全局访问点
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
二、JDK中的运用
public class Runtime {
private static final Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
}