第5章:单例模式(Singleton Pattern)
一、导读
1.1 本章学习目标
第5章讲解单例模式——确保一个类只有一个实例,并提供一个全局访问点。
1.2 为什么第五章如此重要
单例模式看似简单,实则有很多陷阱:线程安全、序列化、延迟初始化等问题需要仔细处理。
1.3 核心问题引导
单例模式有哪些实现方式?
如何保证线程安全?
双重检查锁的原理是什么?
枚举单例为什么是最佳方式?
二、核心概念详解
5.1 经典实现
java
// 懒汉式(线程不安全)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}5.2 线程安全实现
java
// 双重检查锁
public class Singleton {
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;
}
}
// 枚举方式(推荐)
public enum Singleton {
INSTANCE;
public void doSomething() { }
}5.3 单例的问题
单例的反面观点:
- 违反单一职责原则
- 隐藏依赖关系
- 难以测试
- 全局状态
替代方案:
- 依赖注入
- 使用 Spring 的 Bean(默认单例)三、实战案例
3.1 配置管理器
java
public class ConfigManager {
private Map<String, String> config = new HashMap<>();
private ConfigManager() {
// 加载配置
}
private static class Holder {
static final ConfigManager INSTANCE = new ConfigManager();
}
public static ConfigManager getInstance() {
return Holder.INSTANCE;
}
public String get(String key) {
return config.get(key);
}
}四、本章小结
单例确保一个类只有一个实例。枚举方式是最佳实现,双重检查锁需要注意 volatile。但单例有争议,依赖注入是更好的替代方案。
五、思考与练习
单例模式有哪些实现方式?
为什么双重检查锁需要 volatile?
枚举单例为什么是线程安全的?
单例有什么缺点?
依赖注入如何替代单例?