1. 单例模式概述
定义:确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
核心要点:
私有构造函数
静态私有实例
公共静态获取方法
2. 实现方式
2.1 饿汉式(Eager Initialization)
public class EagerSingleton {
// 在类加载时就创建实例
private static final EagerSingleton INSTANCE = new EagerSingleton();
// 私有构造函数
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return INSTANCE;
}
}优点:线程安全,实现简单
缺点:可能造成资源浪费(即使不使用也会创建实例)
2.2 懒汉式(Lazy Initialization)- 非线程安全
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}缺点:多线程环境下不安全
2.3 懒汉式 - 线程安全(同步方法)
public class SynchronizedSingleton {
private static SynchronizedSingleton instance;
private SynchronizedSingleton() {}
// 整个方法加锁,性能较差
public static synchronized SynchronizedSingleton getInstance() {
if (instance == null) {
instance = new SynchronizedSingleton();
}
return instance;
}
}缺点:每次调用都要同步,性能开销大
2.4 双重检查锁定(Double-Checked Locking)
public class DoubleCheckSingleton {
// volatile 确保多线程环境下的可见性和禁止指令重排序
private static volatile DoubleCheckSingleton instance;
private DoubleCheckSingleton() {}
public static DoubleCheckSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckSingleton.class) {
if (instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}优点:线程安全,性能较好
注意:必须使用 volatile 关键字
2.5 静态内部类(推荐)
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {}
// 静态内部类在被调用时才会加载
private static class SingletonHolder {
private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}优点:
线程安全
延迟加载
性能优秀
代码简洁
2.6 枚举实现(最安全)
public enum EnumSingleton {
INSTANCE;
public void doSomething() {
System.out.println("Doing something...");
}
}
// 使用方式
EnumSingleton.INSTANCE.doSomething();优点:
天然线程安全
防止反射攻击
防止序列化破坏单例
代码最简洁
3. 扩展与高级话题
3.1 防止反射破坏单例
public class ReflectionSafeSingleton {
private static volatile ReflectionSafeSingleton instance;
private ReflectionSafeSingleton() {
// 防止通过反射创建多个实例
if (instance != null) {
throw new RuntimeException("Use getInstance() method to create instance!");
}
}
public static ReflectionSafeSingleton getInstance() {
if (instance == null) {
synchronized (ReflectionSafeSingleton.class) {
if (instance == null) {
instance = new ReflectionSafeSingleton();
}
}
}
return instance;
}
}3.2 防止序列化破坏单例
import java.io.Serializable;
public class SerializableSafeSingleton implements Serializable {
private static final long serialVersionUID = 1L;
private static volatile SerializableSafeSingleton instance;
private SerializableSafeSingleton() {}
public static SerializableSafeSingleton getInstance() {
if (instance == null) {
synchronized (SerializableSafeSingleton.class) {
if (instance == null) {
instance = new SerializableSafeSingleton();
}
}
}
return instance;
}
// 保证反序列化时返回同一个实例
private Object readResolve() {
return getInstance();
}
}3.3 泛型单例工厂
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
public class GenericSingletonFactory {
private static final Map<Class<?>, Object> instances = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked")
public static <T> T getInstance(Class<T> clazz) {
return (T) instances.computeIfAbsent(clazz, k -> {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Failed to create instance for " + clazz, e);
}
});
}
}
// 使用示例
MyService service = GenericSingletonFactory.getInstance(MyService.class);3.4 注册表式单例
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
public class RegistrySingleton {
private static final Map<String, Object> registry = new ConcurrentHashMap<>();
private RegistrySingleton() {}
public static void register(String key, Object instance) {
registry.put(key, instance);
}
public static Object getInstance(String key) {
return registry.get(key);
}
public static boolean contains(String key) {
return registry.containsKey(key);
}
}4. 单例模式的适用场景
适用场景:
配置管理器:应用程序配置只需要一份
日志记录器:统一的日志输出管理
数据库连接池:避免重复创建连接
线程池:统一管理线程资源
缓存管理器:全局缓存控制
对话框/窗口管理器:确保界面元素唯一性
不适用场景:
对象需要频繁创建和销毁
对象状态经常变化且需要多个实例
分布式系统中的单例(需要考虑集群环境)
5. 单例模式的优缺点
优点:
内存节约:确保只有一个实例,节省内存
全局访问:提供全局访问点,方便使用
控制实例数量:严格控制对象创建
缺点:
违反单一职责原则:既要管理业务逻辑,又要管理实例创建
难以测试:单例持有状态,影响单元测试的独立性
隐藏依赖关系:通过静态方法获取,依赖关系不明显
扩展困难:单例类通常不能被继承
6. 最佳实践建议
优先考虑枚举实现:最安全、最简洁
次选静态内部类:延迟加载且线程安全
避免使用懒汉式的同步方法:性能太差
考虑使用依赖注入框架:如 Spring 的
@Scope("singleton")注意序列化和反射的安全性
在分布式环境中谨慎使用:考虑 Redis 等分布式解决方案
7. Spring 中的单例
@Component
@Scope("singleton") // 默认就是 singleton
public class SpringSingletonService {
// Spring 容器管理的单例
}Spring 的单例是在 IOC 容器级别,而不是 JVM 级别,这是重要的区别。