news 2026/3/30 20:54:17

单例模式深度解析:七种实现方式详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
单例模式深度解析:七种实现方式详解

一、引言:单例模式的核心思想

1.1 什么是单例模式

单例模式(Singleton Pattern)是设计模式中最简单、最常用的创建型模式之一。其核心思想是确保一个类只有一个实例,并提供一个全局访问点。单例模式不仅控制实例的数量,还简化了全局访问和管理。

1.2 单例模式的典型应用场景

单例模式在软件开发中有着广泛的应用:

  • 配置管理类:系统中的配置信息只需要一个实例管理

  • 数据库连接池:避免频繁创建和销毁连接

  • 日志记录器:统一管理日志输出

  • 线程池:管理线程资源

  • 缓存系统:统一缓存管理

  • Spring框架中的Bean:默认作用域为单例

1.3 单例模式的三个核心特征

  1. 私有构造函数:防止外部直接实例化

  2. 静态私有实例变量:保存类的唯一实例

  3. 静态公共访问方法:提供全局访问点

二、单例模式的七种实现方式详解

2.1 懒汉式(基础版)- 线程不安全

java

/** * 懒汉式单例 - 基础版本(线程不安全) * 特点:延迟加载,但多线程环境下可能创建多个实例 */ public class LazySingleton { private static LazySingleton instance; // 私有构造函数,防止外部实例化 private LazySingleton() { // 防止通过反射创建实例 if (instance != null) { throw new RuntimeException("单例模式禁止反射创建"); } System.out.println("LazySingleton 实例被创建"); } // 公共静态方法,提供全局访问点 public static LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } // 业务方法 public void showMessage() { System.out.println("Hello from LazySingleton!"); } }

实现原理分析:

  1. 将构造函数设为private,防止外部直接new对象

  2. 使用静态变量instance保存唯一实例

  3. 在getInstance()方法中判断实例是否已存在,不存在则创建

线程安全问题分析:

java

// 模拟多线程环境下的问题 public class ThreadUnsafeTest { public static void main(String[] args) { // 创建多个线程同时获取单例 for (int i = 0; i < 10; i++) { new Thread(() -> { LazySingleton singleton = LazySingleton.getInstance(); System.out.println( Thread.currentThread().getName() + "获取的单例哈希码:" + System.identityHashCode(singleton) ); }).start(); } } }

输出可能为:

text

LazySingleton 实例被创建 Thread-0获取的单例哈希码:366712642 LazySingleton 实例被创建 // 再次创建,违反单例原则! Thread-3获取的单例哈希码:1829164700

根本原因:当多个线程同时执行if (instance == null)时,可能都判断为true,从而创建多个实例。

2.2 懒汉式(同步方法版)- 线程安全但性能低

java

/** * 懒汉式单例 - 同步方法版本(线程安全) * 特点:通过synchronized关键字保证线程安全,但性能较低 */ public class SynchronizedLazySingleton { private static SynchronizedLazySingleton instance; private SynchronizedLazySingleton() { System.out.println("SynchronizedLazySingleton 实例被创建"); } // 使用synchronized修饰方法,确保线程安全 public static synchronized SynchronizedLazySingleton getInstance() { if (instance == null) { instance = new SynchronizedLazySingleton(); } return instance; } public void showMessage() { System.out.println("Hello from SynchronizedLazySingleton!"); } }

性能问题分析:

java

public class PerformanceTest { public static void main(String[] args) { long startTime = System.currentTimeMillis(); // 模拟高并发场景 ExecutorService executor = Executors.newFixedThreadPool(100); for (int i = 0; i < 1000; i++) { executor.submit(() -> { SynchronizedLazySingleton singleton = SynchronizedLazySingleton.getInstance(); }); } executor.shutdown(); try { executor.awaitTermination(1, TimeUnit.MINUTES); } catch (InterruptedException e) { e.printStackTrace(); } long endTime = System.currentTimeMillis(); System.out.println("总耗时:" + (endTime - startTime) + "ms"); } }

缺点分析:

  1. 性能瓶颈:每次调用getInstance()都需要获取锁,即使实例已经创建

  2. 锁粒度太粗:整个方法被锁住,无法并发访问

  3. 可能引起线程阻塞:高并发场景下,大量线程排队等待锁

2.3 饿汉式 - 类加载时初始化

java

/** * 饿汉式单例(线程安全) * 特点:在类加载时就创建实例,避免了线程安全问题 */ public class EagerSingleton { // 静态变量在类加载时初始化 private static final EagerSingleton instance = new EagerSingleton(); private EagerSingleton() { System.out.println("EagerSingleton 实例被创建"); } public static EagerSingleton getInstance() { return instance; } public void showMessage() { System.out.println("Hello from EagerSingleton!"); } }

类加载机制深入分析:

java

/** * 验证饿汉式的线程安全性 */ public class ClassLoaderTest { public static void main(String[] args) { // JVM类加载过程保证线程安全 System.out.println("开始加载EagerSingleton类..."); // 获取类加载器 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 模拟多个线程同时加载类 ExecutorService executor = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { executor.submit(() -> { try { // 每个线程都尝试加载类 Class<?> clazz = classLoader.loadClass( "com.pattern.singleton.EagerSingleton" ); // 触发类的初始化 Method getInstance = clazz.getMethod("getInstance"); Object singleton = getInstance.invoke(null); System.out.println( Thread.currentThread().getName() + "获取实例:" + System.identityHashCode(singleton) ); } catch (Exception e) { e.printStackTrace(); } }); } executor.shutdown(); } }

优缺点对比:

优点缺点
1. 实现简单,代码简洁1. 不是延迟加载,可能浪费内存
2. 线程安全,无同步开销2. 如果初始化过程复杂,影响启动速度
3. JVM保证类加载的线程安全3. 不能传递参数进行初始化

使用场景:

  1. 单例对象较小,占用内存少

  2. 初始化过程简单快速

  3. 应用启动时就需要的单例

2.4 双重检查锁定(DCL)- 性能优化的线程安全方案

java

/** * 双重检查锁定单例(Double-Checked Locking) * 特点:延迟加载 + 线程安全 + 高性能 */ public class DoubleCheckedSingleton { // 使用volatile关键字,禁止指令重排序 private static volatile DoubleCheckedSingleton instance; private DoubleCheckedSingleton() { System.out.println("DoubleCheckedSingleton 实例被创建"); } public static DoubleCheckedSingleton getInstance() { // 第一次检查:避免不必要的同步 if (instance == null) { // 同步代码块 synchronized (DoubleCheckedSingleton.class) { // 第二次检查:确保只有一个线程创建实例 if (instance == null) { instance = new DoubleCheckedSingleton(); } } } return instance; } public void showMessage() { System.out.println("Hello from DoubleCheckedSingleton!"); } }

volatile关键字的必要性分析:

java

/** * 模拟没有volatile时的指令重排序问题 */ public class InstructionReorderingExample { private static /*volatile*/ Singleton instance; static class Singleton { private int value; public Singleton() { // 模拟复杂的初始化过程 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } this.value = 42; } public int getValue() { return value; } } public static Singleton getInstance() { if (instance == null) { synchronized (InstructionReorderingExample.class) { if (instance == null) { // 这里可能发生指令重排序! // 正常顺序:1.分配内存 2.初始化对象 3.将引用指向内存地址 // 重排序后:1.分配内存 2.将引用指向内存地址 3.初始化对象 instance = new Singleton(); } } } return instance; } public static void main(String[] args) { // 线程A new Thread(() -> { Singleton s1 = getInstance(); System.out.println("线程A获取value: " + s1.getValue()); }).start(); // 线程B可能在A完成初始化前获取到未完全初始化的对象 new Thread(() -> { Singleton s2 = getInstance(); System.out.println("线程B获取value: " + s2.getValue()); }).start(); } }

DCL模式详细执行流程:

text

线程1进入getInstance(): ↓ 第一次检查: instance == null? Yes ↓ 进入同步块,获取锁 ↓ 第二次检查: instance == null? Yes ↓ 创建实例: instance = new DoubleCheckedSingleton() ↓ 释放锁 ↓ 返回实例 线程2进入getInstance(): ↓ 第一次检查: instance == null? No (volatile保证可见性) ↓ 直接返回实例 (无需同步)

2.5 静态内部类实现 - 优雅的延迟加载方案

java

/** * 静态内部类单例(Holder模式) * 特点:结合了懒加载和线程安全的优点 */ public class InnerClassSingleton { // 私有构造函数 private InnerClassSingleton() { System.out.println("InnerClassSingleton 实例被创建"); } // 静态内部类 private static class SingletonHolder { // 在内部类中创建外部类的实例 private static final InnerClassSingleton INSTANCE = new InnerClassSingleton(); } // 获取实例 public static InnerClassSingleton getInstance() { return SingletonHolder.INSTANCE; } public void showMessage() { System.out.println("Hello from InnerClassSingleton!"); } }

类加载机制原理解析:

java

/** * 验证静态内部类的延迟加载特性 */ public class InnerClassTest { public static void main(String[] args) { System.out.println("程序开始执行..."); // 访问外部类的静态成员,不会触发内部类加载 System.out.println("外部类已加载"); // 第一次调用getInstance()才会加载内部类并创建实例 System.out.println("准备获取单例实例..."); InnerClassSingleton singleton = InnerClassSingleton.getInstance(); System.out.println("实例获取完成"); singleton.showMessage(); } }

输出结果:

text

程序开始执行... 外部类已加载 准备获取单例实例... InnerClassSingleton 实例被创建 实例获取完成 Hello from InnerClassSingleton!

JVM类加载时序图:

text

1. 加载外部类InnerClassSingleton ↓ 2. 解析外部类的符号引用 ↓ 3. 第一次调用getInstance() ↓ 4. 触发SingletonHolder类的加载 ↓ 5. 初始化SingletonHolder类 ↓ 6. 执行静态变量INSTANCE的初始化 ↓ 7. 创建InnerClassSingleton实例

优势分析:

  1. 延迟加载:只有调用getInstance()时才加载内部类

  2. 线程安全:JVM保证类加载的线程安全性

  3. 无同步开销:不需要synchronized关键字

  4. 实现简洁:代码结构清晰

2.6 枚举实现 - 最安全的单例模式

java

/** * 枚举单例(Effective Java推荐方式) * 特点:天生线程安全,防止反射和序列化攻击 */ public enum EnumSingleton { // 单例实例 INSTANCE; // 实例变量 private String data; // 构造方法(默认private) EnumSingleton() { System.out.println("EnumSingleton 实例被创建"); this.data = "初始数据"; } // 业务方法 public void showMessage() { System.out.println("Hello from EnumSingleton!"); } public String getData() { return data; } public void setData(String data) { this.data = data; } }

反编译分析:

java

// 枚举类编译后的等效Java代码 public final class EnumSingleton extends Enum<EnumSingleton> { // 枚举实例被声明为public static final public static final EnumSingleton INSTANCE; private static final EnumSingleton[] $VALUES; static { // 静态初始化块中创建实例 INSTANCE = new EnumSingleton("INSTANCE", 0); $VALUES = new EnumSingleton[] { INSTANCE }; } private EnumSingleton(String name, int ordinal) { super(name, ordinal); System.out.println("EnumSingleton 实例被创建"); this.data = "初始数据"; } // 其他方法... }

防止反射攻击测试:

java

public class ReflectionAttackTest { public static void main(String[] args) throws Exception { // 测试普通单例的反射攻击 testNormalSingleton(); // 测试枚举单例的反射攻击 testEnumSingleton(); } private static void testNormalSingleton() throws Exception { System.out.println("\n=== 测试普通单例的反射攻击 ==="); // 获取构造方法 Constructor<DoubleCheckedSingleton> constructor = DoubleCheckedSingleton.class.getDeclaredConstructor(); constructor.setAccessible(true); // 绕过private // 创建第一个实例 DoubleCheckedSingleton instance1 = DoubleCheckedSingleton.getInstance(); System.out.println("正常获取的实例: " + System.identityHashCode(instance1)); // 通过反射创建第二个实例 DoubleCheckedSingleton instance2 = constructor.newInstance(); System.out.println("反射创建的实例: " + System.identityHashCode(instance2)); System.out.println("两个实例是否相同: " + (instance1 == instance2)); } private static void testEnumSingleton() throws Exception { System.out.println("\n=== 测试枚举单例的反射攻击 ==="); try { // 获取枚举的构造方法(参数为String, int) Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor(String.class, int.class); constructor.setAccessible(true); // 尝试通过反射创建实例 EnumSingleton illegalInstance = constructor.newInstance("ILLEGAL", 1); System.out.println("反射创建的枚举实例: " + System.identityHashCode(illegalInstance)); } catch (Exception e) { System.out.println("反射攻击失败: " + e.getMessage()); } // 正常获取枚举实例 EnumSingleton instance1 = EnumSingleton.INSTANCE; EnumSingleton instance2 = EnumSingleton.INSTANCE; System.out.println("正常获取的两个枚举实例是否相同: " + (instance1 == instance2)); } }

枚举单例的序列化安全性:

java

public class SerializationTest { public static void main(String[] args) throws Exception { System.out.println("=== 序列化测试 ==="); // 测试枚举单例 testEnumSerialization(); // 测试普通单例 testNormalSerialization(); } private static void testEnumSerialization() throws Exception { EnumSingleton instance1 = EnumSingleton.INSTANCE; instance1.setData("修改后的数据"); // 序列化 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(instance1); oos.flush(); // 反序列化 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); EnumSingleton instance2 = (EnumSingleton) ois.readObject(); System.out.println("枚举单例序列化测试:"); System.out.println("instance1 == instance2: " + (instance1 == instance2)); System.out.println("instance1 data: " + instance1.getData()); System.out.println("instance2 data: " + instance2.getData()); } private static void testNormalSerialization() throws Exception { // 需要实现Serializable接口 class SerializableSingleton implements Serializable { private static final long serialVersionUID = 1L; private static SerializableSingleton instance = new SerializableSingleton(); private String data = "初始数据"; private SerializableSingleton() {} public static SerializableSingleton getInstance() { return instance; } // 添加readResolve方法防止序列化破坏 protected Object readResolve() { return getInstance(); } } SerializableSingleton instance1 = SerializableSingleton.getInstance(); instance1.data = "修改后的数据"; // 序列化和反序列化 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(instance1); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); SerializableSingleton instance2 = (SerializableSingleton) ois.readObject(); System.out.println("\n普通单例序列化测试:"); System.out.println("instance1 == instance2: " + (instance1 == instance2)); } }

2.7 ThreadLocal单例 - 线程级别的单例

java

/** * ThreadLocal单例 * 特点:每个线程拥有自己的单例实例 */ public class ThreadLocalSingleton { // ThreadLocal存储每个线程的单例 private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = ThreadLocal.withInitial(() -> { System.out.println(Thread.currentThread().getName() + " 创建 ThreadLocalSingleton 实例"); return new ThreadLocalSingleton(); }); private ThreadLocalSingleton() { System.out.println("ThreadLocalSingleton 构造函数被调用"); } public static ThreadLocalSingleton getInstance() { return threadLocalInstance.get(); } public void showMessage() { System.out.println(Thread.currentThread().getName() + " 的实例: " + System.identityHashCode(this)); } // 重要:使用完成后必须清理,防止内存泄漏 public static void remove() { threadLocalInstance.remove(); } }

ThreadLocal原理分析:

java

/** * ThreadLocal实现原理模拟 */ class ThreadLocalSimulation<T> { // 每个线程都有自己的ThreadLocalMap static class ThreadLocalMap { // 使用WeakReference避免内存泄漏 private Map<ThreadLocal<?>, Object> map = new WeakHashMap<>(); void set(ThreadLocal<?> key, Object value) { map.put(key, value); } Object get(ThreadLocal<?> key) { return map.get(key); } void remove(ThreadLocal<?> key) { map.remove(key); } } public T get() { ThreadLocalMap map = getThreadLocalMap(); if (map == null) { return initialValue(); } return (T) map.get(this); } public void set(T value) { ThreadLocalMap map = getThreadLocalMap(); if (map == null) { map = createThreadLocalMap(); } map.set(this, value); } // 简化实现... }

应用场景示例:

java

public class ThreadLocalSingletonApplication { // 数据库连接上下文(每个线程独立的连接) static class DatabaseConnection { private String connectionId; private ThreadLocal<Connection> connectionHolder = ThreadLocal.withInitial(this::createConnection); private Connection createConnection() { // 模拟创建数据库连接 String connId = "CONN-" + Thread.currentThread().getId() + "-" + System.currentTimeMillis(); System.out.println("线程 " + Thread.currentThread().getName() + " 创建连接: " + connId); return new Connection(connId); } public Connection getConnection() { return connectionHolder.get(); } public void closeConnection() { Connection conn = connectionHolder.get(); if (conn != null) { conn.close(); connectionHolder.remove(); } } static class Connection { private String id; Connection(String id) { this.id = id; } void close() { System.out.println("关闭连接: " + id); } String getId() { return id; } } } public static void main(String[] args) { DatabaseConnection dbManager = new DatabaseConnection(); ExecutorService executor = Executors.newFixedThreadPool(3); for (int i = 0; i < 5; i++) { executor.submit(() -> { // 每个线程获取自己的连接 DatabaseConnection.Connection conn = dbManager.getConnection(); System.out.println(Thread.currentThread().getName() + " 使用的连接: " + conn.getId()); // 模拟业务操作 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // 清理连接 dbManager.closeConnection(); }); } executor.shutdown(); } }

三、单例模式的深入分析

3.1 单例模式的破坏与防护

3.1.1 反射攻击与防护

java

/** * 反射攻击防护的完整方案 */ public class ReflectionProofSingleton { private static volatile ReflectionProofSingleton instance; private static boolean isInstantiated = false; private ReflectionProofSingleton() { // 第一次防护:检查静态标志 synchronized (ReflectionProofSingleton.class) { if (isInstantiated) { throw new RuntimeException("禁止通过反射创建单例实例"); } isInstantiated = true; } System.out.println("ReflectionProofSingleton 被创建"); } public static ReflectionProofSingleton getInstance() { if (instance == null) { synchronized (ReflectionProofSingleton.class) { if (instance == null) { instance = new ReflectionProofSingleton(); } } } return instance; } // 第二次防护:如果单例被反序列化,重置标志 private Object readResolve() { isInstantiated = true; return instance; } }
3.1.2 克隆攻击与防护

java

/** * 防止克隆攻击的单例 */ public class CloneProofSingleton implements Cloneable { private static final CloneProofSingleton instance = new CloneProofSingleton(); private CloneProofSingleton() { System.out.println("CloneProofSingleton 被创建"); } public static CloneProofSingleton getInstance() { return instance; } // 重写clone方法,防止克隆 @Override protected Object clone() throws CloneNotSupportedException { // 直接抛出异常,禁止克隆 throw new CloneNotSupportedException("单例对象不允许克隆"); // 或者返回已有实例 // return instance; } }

3.2 单例模式的性能优化

3.2.1 基于CAS的无锁实现

java

/** * 使用CAS(Compare And Swap)实现的无锁单例 */ public class CASSingleton { private static final AtomicReference<CASSingleton> INSTANCE = new AtomicReference<>(); private CASSingleton() { System.out.println("CASSingleton 被创建"); } public static CASSingleton getInstance() { while (true) { CASSingleton current = INSTANCE.get(); if (current != null) { return current; } current = new CASSingleton(); if (INSTANCE.compareAndSet(null, current)) { return current; } // CAS失败,说明其他线程已经创建了实例,继续循环获取 } } }
3.2.2 性能对比测试

java

public class SingletonPerformanceBenchmark { private static final int THREAD_COUNT = 100; private static final int ITERATIONS = 100000; public static void main(String[] args) throws Exception { System.out.println("=== 单例模式性能测试 ==="); System.out.println("线程数: " + THREAD_COUNT); System.out.println("迭代次数: " + ITERATIONS); // 测试各种实现 testImplementation("饿汉式", () -> EagerSingleton.getInstance()); testImplementation("懒汉式同步方法", () -> SynchronizedLazySingleton.getInstance()); testImplementation("双重检查锁定", () -> DoubleCheckedSingleton.getInstance()); testImplementation("静态内部类", () -> InnerClassSingleton.getInstance()); testImplementation("枚举", () -> EnumSingleton.INSTANCE); testImplementation("CAS无锁", () -> CASSingleton.getInstance()); } private static void testImplementation(String name, Supplier<Object> supplier) throws Exception { System.out.println("\n测试: " + name); // 预热 for (int i = 0; i < 1000; i++) { supplier.get(); } // 正式测试 CountDownLatch startLatch = new CountDownLatch(1); CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT); AtomicLong totalTime = new AtomicLong(0); for (int i = 0; i < THREAD_COUNT; i++) { new Thread(() -> { try { startLatch.await(); long startTime = System.nanoTime(); for (int j = 0; j < ITERATIONS; j++) { supplier.get(); } long endTime = System.nanoTime(); totalTime.addAndGet(endTime - startTime); endLatch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } startLatch.countDown(); endLatch.await(); long avgTime = totalTime.get() / (THREAD_COUNT * ITERATIONS); System.out.println("平均耗时: " + avgTime + " 纳秒"); } }

3.3 单例模式在分布式环境中的挑战

3.3.1 分布式单例实现方案

java

/** * 基于Redis的分布式单例管理器 */ public class DistributedSingletonManager { private static final String REDIS_HOST = "localhost"; private static final int REDIS_PORT = 6379; private static final String SINGLETON_KEY_PREFIX = "singleton:"; private Jedis jedis; public DistributedSingletonManager() { this.jedis = new Jedis(REDIS_HOST, REDIS_PORT); } /** * 获取分布式单例 * @param singletonName 单例名称 * @param creator 实例创建器 * @return 单例实例(JSON格式) */ public String getSingleton(String singletonName, Supplier<String> creator) { String key = SINGLETON_KEY_PREFIX + singletonName; // 尝试获取锁 String lockKey = key + ":lock"; String requestId = UUID.randomUUID().toString(); try { // 使用Redis分布式锁 boolean locked = tryGetDistributedLock(lockKey, requestId, 5000); if (locked) { try { // 检查实例是否存在 String instance = jedis.get(key); if (instance == null) { // 创建实例 instance = creator.get(); jedis.setex(key, 3600, instance); // 设置1小时过期 } return instance; } finally { // 释放锁 releaseDistributedLock(lockKey, requestId); } } else { // 等待其他节点创建实例 Thread.sleep(100); return jedis.get(key); } } catch (Exception e) { throw new RuntimeException("获取分布式单例失败", e); } } private boolean tryGetDistributedLock(String lockKey, String requestId, long expireTime) { // 使用SETNX命令实现分布式锁 String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime); return "OK".equals(result); } private void releaseDistributedLock(String lockKey, String requestId) { // 使用Lua脚本保证原子性 String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " + " return redis.call('del', KEYS[1]) " + "else " + " return 0 " + "end"; jedis.eval(luaScript, 1, lockKey, requestId); } }

四、单例模式的扩展与变种

4.1 多例模式(Multiton Pattern)

java

/** * 多例模式:有限数量的单例 */ public class Multiton { // 存储多个实例 private static final Map<String, Multiton> instances = new ConcurrentHashMap<>(); // 最大实例数量 private static final int MAX_INSTANCES = 3; private String name; private Multiton(String name) { this.name = name; System.out.println("创建Multiton实例: " + name); } /** * 根据名称获取实例 */ public static Multiton getInstance(String name) { return instances.computeIfAbsent(name, key -> { if (instances.size() >= MAX_INSTANCES) { throw new IllegalStateException("超过最大实例数量限制: " + MAX_INSTANCES); } return new Multiton(key); }); } /** * 获取所有实例 */ public static Collection<Multiton> getAllInstances() { return instances.values(); } /** * 清理实例 */ public static void clear() { instances.clear(); } public String getName() { return name; } }

4.2 线程单例模式

java

/** * 线程单例:每个线程有自己的单例,但不同线程的单例不同 */ public class ThreadSingletonRegistry { // 存储不同类型的线程单例 private static final ThreadLocal<Map<Class<?>, Object>> threadSingletons = ThreadLocal.withInitial(WeakHashMap::new); /** * 获取线程单例 */ @SuppressWarnings("unchecked") public static <T> T getInstance(Class<T> clazz) { Map<Class<?>, Object> map = threadSingletons.get(); return (T) map.computeIfAbsent(clazz, key -> { try { return clazz.newInstance(); } catch (Exception e) { throw new RuntimeException("创建实例失败: " + clazz.getName(), e); } }); } /** * 注册线程单例 */ public static <T> void registerInstance(Class<T> clazz, T instance) { Map<Class<?>, Object> map = threadSingletons.get(); map.put(clazz, instance); } /** * 清理当前线程的所有单例 */ public static void clear() { threadSingletons.remove(); } }

4.3 单例工厂模式

java

/** * 单例工厂:统一管理多个单例 */ public class SingletonFactory { // 注册表存储所有单例 private static final Map<String, Object> singletonRegistry = new ConcurrentHashMap<>(); // 防止实例化 private SingletonFactory() {} /** * 获取单例 */ @SuppressWarnings("unchecked") public static <T> T getSingleton(String name, Supplier<T> creator) { return (T) singletonRegistry.computeIfAbsent(name, key -> creator.get()); } /** * 注册单例 */ public static void registerSingleton(String name, Object singleton) { if (singletonRegistry.containsKey(name)) { throw new IllegalArgumentException("单例已存在: " + name); } singletonRegistry.put(name, singleton); } /** * 获取所有单例名称 */ public static Set<String> getAllSingletonNames() { return singletonRegistry.keySet(); } /** * 销毁单例 */ public static void destroySingleton(String name) { Object singleton = singletonRegistry.remove(name); if (singleton instanceof AutoCloseable) { try { ((AutoCloseable) singleton).close(); } catch (Exception e) { // 记录日志 } } } /** * 销毁所有单例 */ public static void destroyAll() { List<String> names = new ArrayList<>(singletonRegistry.keySet()); for (String name : names) { destroySingleton(name); } } }

五、单例模式的最佳实践

5.1 选择合适实现方式的决策树

text

开始 ↓ 是否需要延迟加载? ├── 否 → 选择饿汉式或枚举 │ ├── 需要防止反射/序列化攻击 → 选择枚举 │ └── 不需要 → 选择饿汉式 │ └── 是 → 性能要求高吗? ├── 是 → 需要绝对线程安全吗? │ ├── 是 → 选择双重检查锁定(DCL) │ └── 否 → 选择静态内部类 │ └── 否 → 选择懒汉式(同步方法)

5.2 代码规范与注意事项

java

/** * 单例模式的最佳实践示例 */ public class BestPracticeSingleton { // 1. 使用volatile保证可见性和禁止指令重排序 private static volatile BestPracticeSingleton instance; // 2. 添加版本号,便于序列化 private static final long serialVersionUID = 1L; // 3. 添加标志防止反射攻击 private static boolean initialized = false; // 4. 实例变量 private final String configuration; // 5. 私有构造函数 private BestPracticeSingleton() { // 防止反射攻击 synchronized (BestPracticeSingleton.class) { if (initialized) { throw new RuntimeException("禁止通过反射创建单例"); } initialized = true; } // 初始化配置 this.configuration = loadConfiguration(); System.out.println("BestPracticeSingleton 初始化完成"); } // 6. 公共静态访问方法 public static BestPracticeSingleton getInstance() { // 双重检查锁定 if (instance == null) { synchronized (BestPracticeSingleton.class) { if (instance == null) { instance = new BestPracticeSingleton(); } } } return instance; } // 7. 防止序列化破坏 private Object readResolve() { return getInstance(); } // 8. 防止克隆 @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException("单例对象不允许克隆"); } // 9. 清理方法(如果需要) public void destroy() { // 清理资源 initialized = false; instance = null; } // 10. 业务方法 public String getConfiguration() { return configuration; } private String loadConfiguration() { // 模拟加载配置 return "应用配置"; } }

5.3 Spring框架中的单例实践

java

/** * Spring单例Bean的模拟实现 */ @Component @Scope("singleton") // 默认就是singleton,可以省略 public class SpringSingletonBean implements InitializingBean, DisposableBean, ApplicationContextAware { private static final Logger logger = LoggerFactory.getLogger(SpringSingletonBean.class); private ApplicationContext applicationContext; // 实例变量 private Map<String, Object> cache = new ConcurrentHashMap<>(); /** * 构造函数(Spring通过反射调用) */ public SpringSingletonBean() { logger.info("SpringSingletonBean 构造函数被调用"); } /** * 初始化方法 */ @PostConstruct public void init() { logger.info("SpringSingletonBean @PostConstruct 初始化"); // 初始化缓存 cache.put("initialized", true); cache.put("startTime", System.currentTimeMillis()); } /** * InitializingBean接口方法 */ @Override public void afterPropertiesSet() throws Exception { logger.info("SpringSingletonBean afterPropertiesSet 初始化"); } /** * 业务方法 */ public Object getFromCache(String key) { return cache.get(key); } public void putToCache(String key, Object value) { cache.put(key, value); } /** * 销毁前清理 */ @PreDestroy public void preDestroy() { logger.info("SpringSingletonBean @PreDestroy 清理"); cache.clear(); } /** * DisposableBean接口方法 */ @Override public void destroy() throws Exception { logger.info("SpringSingletonBean destroy 清理"); } /** * ApplicationContextAware接口方法 */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }

六、总结

6.1 七种实现方式对比总结

实现方式线程安全延迟加载防止反射防止序列化性能实现复杂度
懒汉式(基础)
懒汉式(同步方法)
饿汉式✅*❌*
双重检查锁定✅*❌*
静态内部类✅*❌*
枚举
ThreadLocal✅*✅*❌*

注:需要额外处理才能达到该效果

6.2 选择建议

  1. 简单场景:如果不需要延迟加载,枚举是最佳选择

  2. 需要延迟加载静态内部类实现是最优雅的方式

  3. 需要考虑反射和序列化:优先选择枚举实现

  4. 性能要求极高:考虑饿汉式双重检查锁定

  5. 线程隔离需求:选择ThreadLocal单例

  6. Spring环境:直接使用Spring的单例Bean管理

6.3 单例模式的局限性

虽然单例模式有很多优点,但也存在一些局限性:

  1. 测试困难:单例的全局状态可能影响单元测试的独立性

  2. 隐藏依赖:单例的使用可能隐藏类之间的依赖关系

  3. 违反单一职责:单例类同时负责创建实例和管理业务逻辑

  4. 可能成为性能瓶颈:如果单例包含同步代码,可能成为并发瓶颈

6.4 未来发展趋势

随着云原生和微服务架构的流行,单例模式也在演进:

  1. 分布式单例:在分布式系统中实现单例逻辑

  2. 函数式编程:使用不可变对象替代传统单例

  3. 依赖注入:通过IoC容器管理单例生命周期

  4. 响应式编程:单例模式的响应式版本

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 10:52:34

Qwen-Image-Edit-2511支持动态分辨率,适配多场景

Qwen-Image-Edit-2511 支持动态分辨率&#xff0c;适配多场景&#xff1a;图像编辑的精准控制新范式 你有没有试过这样编辑一张图——想把咖啡杯换成青花瓷杯&#xff0c;结果整张桌子都变了风格&#xff1f; 想给产品图加个玻璃展台&#xff0c;结果背景里的模特也跟着“长”…

作者头像 李华
网站建设 2026/3/27 10:09:12

手动部署jar包,太low!我推荐一个官方神器!

平时使用SpringBoot开发项目的时候&#xff0c;如果要部署到服务器上&#xff0c;修改代码后需要上传jar包才能实现&#xff0c;这种方式比较麻烦&#xff01;那么有没有什么办法能自动部署更新后的项目呢&#xff1f;今天给大家分享一款SpringBoot官方的热部署工具spring-boot…

作者头像 李华
网站建设 2026/3/27 6:22:15

Node.js用once监听器防内存泄漏

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Node.js内存泄漏的隐形杀手&#xff1a;为何once监听器是你的防泄漏神器目录Node.js内存泄漏的隐形杀手&#xff1a;为何once监听…

作者头像 李华
网站建设 2026/3/27 16:56:04

langchain 快速入门(四):搭建强大的AI Agent

简介 AI Agent 不仅仅是一个能聊天的机器人&#xff08;如普通的 ChatGPT&#xff09;&#xff0c;而是一个能够感知环境、进行推理、自主决策并调用工具来完成特定任务的智能系统&#xff0c;更够完成更为复杂的AI场景需求。 AI Agent 功能 根据查阅的资料&#xff0c;agent的…

作者头像 李华
网站建设 2026/3/27 0:25:36

Python篇---模块化编程

一、什么是模块化编程&#xff1f; 想象一下你要盖一座房子&#xff1a; 你不会把所有材料堆在一起&#xff0c;而是会分成&#xff1a; 地基模块 墙壁模块 屋顶模块 门窗模块 模块化编程就是把代码分成多个独立的“积木块”&#xff0c;每个积木块负责特定的功能。 二…

作者头像 李华