1. 单例模式基础认知
第一次接触单例模式是在2013年参与一个物联网网关项目时。当时系统需要全局管理设备连接状态,多个服务模块都要访问同一份连接数据。如果每个模块都自己维护状态副本,不仅内存浪费,更会导致状态不一致。团队里的架构师老张拍了拍我肩膀说:"小伙子,该用单例了。"
单例模式(Singleton Pattern)作为创建型设计模式中最简单却最常用的一种,其核心在于确保一个类只有一个实例,并提供一个全局访问点。就像公司里的CEO职位,无论哪个部门要请示汇报,找的都是同一位领导。
在实际开发中,这些场景特别适合单例:
- 配置信息管理(如数据库连接参数)
- 日志记录器(避免日志文件被多个实例争抢)
- 设备驱动(比如打印机后台服务)
- 线程池/连接池管理
- 缓存系统实现
重要提示:不要仅仅为了"方便调用"就滥用单例。我曾见过有开发者把工具类全部做成单例,结果导致单元测试难以隔离,系统耦合度飙升。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 单例模式的六种实现方式演变
2.1 饿汉式:简单粗暴的起手式
java复制public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
这是我最开始学到的实现方式。类加载时就立即初始化实例,就像个急不可耐的吃货,饭还没端上桌就先拿好了筷子。优点是实现简单且线程安全,但缺点也很明显:
- 可能造成资源浪费(实例一直占用内存)
- 无法传递初始化参数(因为构造时机不可控)
在Spring框架的Bean管理中,默认就是这种单例策略,不过Spring通过容器管理解决了资源浪费的问题。
2.2 懒汉式:拖延症患者的解决方案
java复制public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
等真正需要时才创建实例,就像拖延到最后一刻才开始写作业的学生。虽然解决了资源问题,但每次获取实例都要同步锁,性能堪忧。我在一次压力测试中发现,这种实现方式QPS比饿汉式下降了40%。
2.3 双重检查锁:性能与安全的平衡术
java复制public class DCLSingleton {
private volatile static DCLSingleton instance;
private DCLSingleton() {}
public static DCLSingleton getInstance() {
if (instance ==
