导读
单例模式(Singleton Pattern)是一种创建型设计模式 ,它确保一个类在整个应用程序生命周期中只有一个实例存在,并提供一个全局访问点来获取该实例。
在 Java 中,常见的实现方式主要有两种:饿汉式(Eager Initialization) 和 懒汉式(Lazy Initialization)。它们各有优缺点,适用于不同场景。
实现方式 | 是否延迟加载 | 是否线程安全 | 是否推荐 |
---|---|---|---|
饿汉式 | ❌ 否 | ✅ 是 | ✅ 推荐(简单场景) |
懒汉式(无锁) | ✅ 是 | ❌ 否 | ❌ 不推荐 |
懒汉式(synchronized) | ✅ 是 | ✅ 是 | ⚠️ 可接受(性能略差) |
双重检查锁定 | ✅ 是 | ✅ 是 | ✅ 推荐 |
静态内部类 | ✅ 是 | ✅ 是 | ✅ 推荐 |
枚举 | ✅ 是 | ✅ 是 | ✅✅ 最推荐 |
🎯 应用场景
- 数据库连接池管理
- 日志记录器(如 Logger)
- 配置管理类(如
Properties
) - Spring 中的 Bean 默认就是单例模式
一、饿汉式(Eager Initialization)
特点 :类加载时立即创建实例(急切初始化)
优点 :线程安全,无需加锁(由 JVM 类加载机制保证)
缺点:可能造成资源浪费(未使用时也占用内存)
1. 基础实现(静态变量)
java
public class EagerSingleton {
// 类加载时初始化实例
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {} // 私有构造器
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
2. 静态代码块变体
java
public class EagerSingleton {
private static final EagerSingleton INSTANCE;
static {
try {
INSTANCE = new EagerSingleton();
} catch (Exception e) {
throw new RuntimeException("初始化失败", e);
}
}
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
3. 枚举实现(终极方案)
java
public enum EnumSingleton {
INSTANCE; // 单例实例
public void doSomething() {
// 业务方法
}
}
// 使用:EnumSingleton.INSTANCE.doSomething();
优势:
- 绝对防止反射攻击
- 自动处理序列化/反序列化
- 线程安全
- 代码最简洁(Java 官方推荐方式)
二、懒汉式(Lazy Initialization)
特点 :首次使用时创建实例(延迟初始化)
优点 :节省资源
缺点:需额外处理线程安全问题
1. 非线程安全基础版
java
public class UnsafeLazySingleton {
private static UnsafeLazySingleton instance;
private UnsafeLazySingleton() {}
public static UnsafeLazySingleton getInstance() {
if (instance == null) { // 线程不安全点
instance = new UnsafeLazySingleton();
}
return instance;
}
}
2. 线程安全同步方法版(低效)
java
public class SynchronizedLazySingleton {
private static SynchronizedLazySingleton instance;
private SynchronizedLazySingleton() {}
public static synchronized SynchronizedLazySingleton getInstance() {
if (instance == null) {
instance = new SynchronizedLazySingleton();
}
return instance;
}
}
缺点:每次获取实例都同步,性能差
3. 双重检查锁定(DCL)版(高效线程安全)
java
public class DoubleCheckedLockingSingleton {
// volatile 禁止指令重排序
private static volatile DoubleCheckedLockingSingleton instance;
private DoubleCheckedLockingSingleton() {}
public static DoubleCheckedLockingSingleton getInstance() {
if (instance == null) { // 第一次检查(无锁)
synchronized (DoubleCheckedLockingSingleton.class) {
if (instance == null) { // 第二次检查(有锁)
instance = new DoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
关键点:
volatile
防止 JVM 指令重排序(避免返回未初始化的对象)- 两次判空确保单例
4. 静态内部类(Holder)模式(推荐)
java
public class HolderSingleton {
private HolderSingleton() {}
private static class Holder {
// 由 JVM 保证线程安全初始化
static final HolderSingleton INSTANCE = new HolderSingleton();
}
public static HolderSingleton getInstance() {
return Holder.INSTANCE; // 首次调用时加载 Holder 类
}
}
优势:
- 线程安全(JVM 类加载机制)
- 懒加载(调用
getInstance()
时才初始化) - 无同步开销
五、选型建议
-
首选枚举方案(Java 5+)
- 满足所有安全需求
- 代码简洁明了(《Effective Java》推荐)
-
需要懒加载时
- 选静态内部类(平衡安全性与性能)
- 避免使用基础同步方法(性能差)
-
明确需要饿加载
- 简单场景用饿汉式
- 需异常处理时用静态块变体
-
超高性能场景
- 首选枚举 或饿汉式
- 次选双重检查锁定(注意 volatile)
📌 设计原则:在满足需求的前提下,选择最简单的实现。单例模式已被认为是一种"反模式",过度使用会导致代码耦合度高、难以测试,建议结合依赖注入框架(如Spring)管理单例。