单例
更新: 6/28/2025 字数: 0 字 时长: 0 分钟
定义
单例模式 (Singleton Pattern) 确保一个类只有一个实例,并提供全局访问点。该模式通过私有化构造器、提供静态获取方法来实现对象的唯一性控制。
角色
- 单例类 (Singleton):包含私有静态实例变量、私有构造器、公共静态访问方法
实现
饿汉式(线程安全)
java
public class EagerSingleton {
// 类加载时立即初始化
private static final EagerSingleton instance = new EagerSingleton();
// 私有构造器防止外部实例化
private EagerSingleton() {
System.out.println("饿汉式单例初始化");
}
public static EagerSingleton getInstance() {
return instance;
}
}
懒汉式(线程不安全)
java
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
System.out.println("懒汉式单例初始化");
}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
线程安全懒汉式(双重检查锁定)
java
public class ThreadSafeSingleton {
private static volatile ThreadSafeSingleton instance;
private ThreadSafeSingleton() {
System.out.println("线程安全单例初始化");
}
public static ThreadSafeSingleton getInstance() {
if (instance == null) {
synchronized (ThreadSafeSingleton.class) {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}
}
静态内部类实现(推荐)
java
public class StaticInnerSingleton {
private StaticInnerSingleton() {
System.out.println("静态内部类单例初始化");
}
private static class SingletonHolder {
private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();
}
public static StaticInnerSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举实现(最佳实践)
java
public enum EnumSingleton {
INSTANCE;
public void doSomething() {
System.out.println("枚举单例方法执行");
}
}
优缺点
优点:
- 严格控制实例数量,节省系统资源
- 全局访问点便于管理和扩展
- 避免频繁创建销毁对象,提高性能
缺点:
- 扩展困难(需要修改单例类本身)
- 违背单一职责原则(同时承担实例控制和业务逻辑)
- 多线程环境下需要特殊处理
- 单元测试困难(无法模拟替代实现)
应用场景
- 需要频繁创建销毁但又要控制数量的对象(线程池、缓存)
- 需要全局访问点的共享资源(配置管理、日志系统)
- 重量级资源对象(数据库连接池、文件系统)
- 需要唯一实例的核心组件(任务管理器、设备驱动程序)
与其他模式的关系
- 与工厂模式:单例常作为工厂模式的实现基础(如抽象工厂中的具体工厂)
- 与享元模式:都是对象复用技术,但单例确保唯一实例,享元管理多个相似对象
- 与状态模式:状态对象常设计为单例
- 与门面模式:门面对象通常实现为单例
JDK 中的单例模式
java.lang.Runtime
:饿汉式实现java.awt.Desktop
:懒汉式实现java.lang.System
:系统级单例java.util.Collections#EMPTY_LIST
:不可变空集合单例
注意事项
- 序列化攻击:实现
readResolve()
方法防止反序列化创建新实例 - 反射攻击:构造器中添加防止重复初始化的检查
- 克隆攻击:重写
clone()
方法并抛出异常