单例模式详解:从基础到高级的八种实现方式
单例模式简介
单例模式是一种常用的软件设计模式,其核心定义是:一个类只能允许存在一个实例,并提供一个全局访问点来获取该实例。
应用场景
- 服务器配置信息管理
- 数据库连接池
- 日志管理器
- 应用计数器
- 线程池
单例模式的基本实现思路
- 私有化构造方法:防止外部通过new关键字创建实例
- 提供静态访问方法:通过静态方法返回类的唯一实例
单例模式的八种实现方式
1. 饿汉式(静态常量)✅
public class Singleton {private final static Singleton INSTANCE = new Singleton();private Singleton() {}public static Singleton getInstance() {return INSTANCE;}
}
优点:线程安全,实现简单
缺点:类加载时就初始化,可能造成内存浪费
2. 饿汉式(静态代码块)✅
public class Singleton {private static Singleton instance;static {instance = new Singleton();}private Singleton() {}public static Singleton getInstance() {return instance;}
}
与静态常量方式类似,只是实例化过程放在静态代码块中。
3. 懒汉式(线程不安全)❌
public class Singleton {private static Singleton singleton;private Singleton() {}public static Singleton getInstance() {if (singleton == null) {singleton = new Singleton();}return singleton;}
}
问题:多线程环境下可能创建多个实例
4. 懒汉式(同步方法)⚠️
public class Singleton {private static Singleton singleton;private Singleton() {}public static synchronized Singleton getInstance() {if (singleton == null) {singleton = new Singleton();}return singleton;}
}
优点:线程安全
缺点:同步粒度太大,性能较差
5. 懒汉式(同步代码块)❌
public class Singleton {private static Singleton singleton;private Singleton() {}public static Singleton getInstance() {if (singleton == null) {synchronized (Singleton.class) {singleton = new Singleton();}}return singleton;}
}
问题:仍然存在线程安全问题,无法完全保证单例
6. 双重检查锁定 ✅
public class Singleton {private static volatile Singleton singleton;private Singleton() {}public static Singleton getInstance() {if (singleton == null) {synchronized (Singleton.class) {if (singleton == null) {singleton = new Singleton();}}}return singleton;}
}
关键点:
volatile关键字防止指令重排序- 两次null检查确保线程安全
- 同步块内再次检查避免多实例
优点:线程安全、延迟加载、效率高
7. 静态内部类 ✅
public class Singleton {private Singleton() {}private static class SingletonInstance {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonInstance.INSTANCE;}
}
原理:利用类加载机制保证线程安全,静态内部类在首次调用getInstance()时才会加载
优点:线程安全、实现简单、延迟加载
8. 枚举 ✅
public enum Singleton {INSTANCE;public void whateverMethod() {// 业务方法}
}
优势:
- 绝对防止多实例创建
- 天然防止反射攻击
- 自动支持序列化机制
- 代码简洁
单例模式的进阶考虑
反射攻击防护
public class Singleton {private static volatile Singleton instance;private Singleton() {// 防止反射攻击if (instance != null) {throw new RuntimeException("单例模式禁止通过反射创建实例");}}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
序列化安全
public class Singleton implements Serializable {private static final long serialVersionUID = 1L;private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private Singleton() {}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}// 防止反序列化创建新实例protected Object readResolve() {return getInstance();}
}
总结对比
| 实现方式 | 线程安全 | 延迟加载 | 性能 | 防止反射 | 防止序列化 |
|---|---|---|---|---|---|
| 饿汉式 | ✅ | ❌ | 高 | ❌ | ❌ |
| 懒汉式(不安全) | ❌ | ✅ | 高 | ❌ | ❌ |
| 同步方法 | ✅ | ✅ | 低 | ❌ | ❌ |
| 双重检查 | ✅ | ✅ | 高 | ❌ | ❌ |
| 静态内部类 | ✅ | ✅ | 高 | ❌ | ❌ |
| 枚举 | ✅ | ❌ | 高 | ✅ | ✅ |
最佳实践建议
- 追求简单:使用静态内部类方式
- 需要防反射:使用枚举方式
- 明确不需要延迟加载:使用饿汉式
- JDK 1.5+环境:优先考虑双重检查+volatile
- 考虑序列化:实现
readResolve()方法
单例模式虽然常用,但在分布式系统、微服务架构中需要谨慎使用,避免成为系统瓶颈。
