| 序号 | 实现方式 | 线程安全 | 懒加载 | 性能 | 防止反射破坏 | 防止序列化破坏 | 代码复杂度 | 适用场景 |
|---|---|---|---|---|---|---|---|---|
| 1 | 饿汉式 | 是 | 否 | 高 | ❌ | ❌ | 低 | 单线程环境简单应用 |
| 2 | 懒汉式(线程不安全) | 否 | 是 | 高 | ❌ | ❌ | 低 | 单线程环境,性能要求高 |
| 3 | 懒汉式(方法同步) | 是 | 是 | 低 | ❌ | ❌ | 中 | 多线程但性能要求不高 |
| 4 | 双重检查锁(DCL) | 是 | 是 | 高 | ❌ | ❌ | 中 | 多线程,性能要求高 |
| 5 | 静态内部类 | 是 | 是 | 高 | ❌ | ❌ | 中 | 推荐使用,兼顾性能和懒加载 |
| 6 | 枚举 | 是 | 否 | 高 | ✅ | ✅ | 低 | 最佳实践,保证绝对单例 |
| 7 | ThreadLocal单例 | 线程内安全 | 是 | 中 | ❌ | ❌ | 高 | 线程池环境,线程隔离单例 |
详细说明
1. 饿汉式
java
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
优点 : 实现简单,线程安全
缺点: 类加载时就初始化,浪费内存
2. 懒汉式(线程不安全)
java
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
优点 : 懒加载,需要时才创建
缺点: 线程不安全,可能创建多个实例
3. 懒汉式(方法同步)
java
public class SyncSingleton {
private static SyncSingleton instance;
private SyncSingleton() {}
public static synchronized SyncSingleton getInstance() {
if (instance == null) {
instance = new SyncSingleton();
}
return instance;
}
}
优点 : 线程安全,懒加载
缺点: 每次获取都加锁,性能差
4. 双重检查锁(DCL)
java
public class DCLSingleton {
private volatile static DCLSingleton instance;
private DCLSingleton() {}
public static DCLSingleton getInstance() {
if (instance == null) {
synchronized (DCLSingleton.class) {
if (instance == null) {
instance = new DCLSingleton();
}
}
}
return instance;
}
}
优点 : 线程安全,懒加载,性能较好
缺点: JDK1.5+才完全安全,实现稍复杂
5. 静态内部类
java
public class InnerClassSingleton {
private InnerClassSingleton() {}
private static class SingletonHolder {
private static final InnerClassSingleton instance = new InnerClassSingleton();
}
public static InnerClassSingleton getInstance() {
return SingletonHolder.instance;
}
}
优点 : 线程安全,懒加载,性能好
缺点: 无法防止反射破坏
6. 枚举(最佳实践)
java
public enum EnumSingleton {
INSTANCE;
public void doSomething() {
// 业务方法
}
}
优点:
-
绝对防止反射破坏
-
自动处理序列化
-
线程安全
-
代码简洁
缺点: 不是懒加载,枚举类加载时就初始化
7. ThreadLocal单例
java
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocal =
ThreadLocal.withInitial(ThreadLocalSingleton::new);
private ThreadLocalSingleton() {}
public static ThreadLocalSingleton getInstance() {
return threadLocal.get();
}
}
优点 : 线程内单例,适合线程池环境
缺点: 每个线程有自己的实例,不是真正的全局单例
选择建议
-
简单场景:饿汉式
-
标准需求:静态内部类(推荐)
-
严格要求:枚举(最佳实践)
-
线程隔离:ThreadLocal单例
-
历史遗留:DCL(注意volatile关键字)
注意事项
-
反射攻击防护:只有枚举能天然防止反射破坏,其他方式需要额外防护代码
-
序列化问题:实现Serializable接口时,需要添加readResolve()方法
-
克隆防护:重写clone()方法,抛出CloneNotSupportedException
-
多类加载器:自定义类加载器可能破坏单例,需注意类加载器隔离