Java中的设计模式:单例模式详解
字数 790 2025-11-05 23:47:54
Java中的设计模式:单例模式详解
描述
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。这种设计模式在需要控制资源访问(如数据库连接池、配置管理器、日志记录器等)的场景中非常有用。
核心要点
- 私有化构造函数:防止外部通过new创建实例
- 静态私有成员变量:存储唯一实例
- 静态公有方法:提供全局访问入口
演进过程
1. 饿汉式(Eager Initialization)
public class Singleton {
// 类加载时就创建实例
private static final Singleton INSTANCE = new Singleton();
// 私有构造函数
private Singleton() {}
// 全局访问点
public static Singleton getInstance() {
return INSTANCE;
}
}
- 优点:实现简单,线程安全
- 缺点:如果实例未被使用,会造成内存浪费
2. 懒汉式(Lazy Initialization)
public class Singleton {
private static Singleton instance;
private Singleton() {}
// 需要时才创建实例
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 优点:延迟加载,节省内存
- 缺点:线程不安全,多线程环境下可能创建多个实例
3. 线程安全的懒汉式
public class Singleton {
private static Singleton instance;
private Singleton() {}
// 方法同步,保证线程安全
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 优点:线程安全
- 缺点:每次获取实例都要同步,性能较差
4. 双重检查锁(Double-Checked Locking)
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;
}
}
- 第一次检查:避免不必要的同步
- 第二次检查:确保只有一个线程创建实例
- volatile关键字:防止JVM指令重排序导致的空指针问题
5. 静态内部类(Holder)方式
public class Singleton {
private Singleton() {}
// 静态内部类在第一次使用时加载
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
- 优点:线程安全,延迟加载,性能好
- 原理:利用类加载机制保证线程安全
6. 枚举方式(推荐)
public enum Singleton {
INSTANCE;
public void doSomething() {
// 业务方法
}
}
- 优点:线程安全,防止反射攻击,防止反序列化重新创建对象
- 这是《Effective Java》作者Joshua Bloch推荐的方式
关键问题解析
1. 为什么需要两次null检查?
- 第一次检查:避免不必要的同步,提高性能
- 第二次检查:确保在同步块内只有一个线程能创建实例
2. volatile关键字的作用
instance = new Singleton(); // 这行代码分为3步:
// 1. 分配内存空间
// 2. 初始化对象
// 3. 将instance指向内存地址
如果没有volatile,可能发生指令重排序,导致其他线程拿到未初始化的对象。
3. 防止反射攻击
public class Singleton {
private static boolean initialized = false;
private Singleton() {
synchronized (Singleton.class) {
if (initialized) {
throw new RuntimeException("单例模式被破坏!");
}
initialized = true;
}
}
}
使用场景
- 需要频繁创建和销毁的对象
- 创建对象耗时过多或资源消耗过大
- 工具类对象
- 数据库连接池等资源管理器
每种实现方式都有其适用场景,应根据具体需求选择最合适的实现方案。