2026/5/21 9:54:04
网站建设
项目流程
乐清网站推广,wordpress无法添加区块,国美网上商城官网,中国建设集团官网1. 单例模式概述1.1 什么是单例模式单例模式#xff08;Singleton Pattern#xff09;是一种创建型设计模式#xff0c;它确保一个类只有一个实例#xff0c;并提供一个全局访问点来访问这个实例。1.2 单例模式的三大要素私有构造方法#xff1a;防止外部通过new创建实例静…1. 单例模式概述1.1 什么是单例模式单例模式Singleton Pattern是一种创建型设计模式它确保一个类只有一个实例并提供一个全局访问点来访问这个实例。1.2 单例模式的三大要素私有构造方法防止外部通过new创建实例静态私有实例存储类的唯一实例静态公有方法提供全局访问点1.3 单例模式的适用场景需要频繁创建和销毁的对象创建对象耗时过多或资源消耗过大工具类对象频繁访问数据库或文件的对象需要共享访问点或共享数据的场景2. 饿汉式静态常量2.1 实现代码java/** * 饿汉式静态常量 * 优点写法简单类装载时就完成实例化避免了线程同步问题 * 缺点没有达到Lazy Loading的效果如果从始至终未使用过这个实例则会造成内存浪费 */ public class Singleton1 { // 1. 私有构造方法 private Singleton1() { // 防止反射破坏单例 if (instance ! null) { throw new RuntimeException(单例对象不能重复创建); } System.out.println(Singleton1 实例化); } // 2. 静态私有实例 private static final Singleton1 instance new Singleton1(); // 3. 静态公有方法 public static Singleton1 getInstance() { return instance; } // 防止反序列化破坏单例 public Object readResolve() { return instance; } }2.2 优缺点分析优点实现简单线程安全没有同步开销性能好缺点不是延迟加载类加载时就初始化如果实例一直没被使用会造成资源浪费不能防止反射和反序列化攻击需要额外处理3. 饿汉式静态代码块3.1 实现代码java/** * 饿汉式静态代码块 * 优缺点与静态常量方式相同 */ public class Singleton2 { private Singleton2() { // 防止反射攻击 if (instance ! null) { throw new RuntimeException(单例对象不能重复创建); } System.out.println(Singleton2 实例化); } private static Singleton2 instance; // 静态代码块中创建实例 static { instance new Singleton2(); } public static Singleton2 getInstance() { return instance; } // 防止反序列化破坏单例 public Object readResolve() { return instance; } }3.2 与静态常量方式的区别实例化过程可以放在静态代码块中适合复杂的初始化本质上与静态常量方式相同都是类加载时初始化4. 懒汉式线程不安全4.1 实现代码java/** * 懒汉式线程不安全 * 优点延迟加载需要时才创建 * 缺点线程不安全多线程下可能创建多个实例 */ public class Singleton3 { private Singleton3() { System.out.println(Singleton3 实例化); } private static Singleton3 instance; public static Singleton3 getInstance() { if (instance null) { instance new Singleton3(); } return instance; } }4.2 线程安全问题分析java// 模拟多线程环境下的问题 public class SingletonTest { public static void main(String[] args) { ExecutorService executor Executors.newFixedThreadPool(10); SetSingleton3 set Collections.synchronizedSet(new HashSet()); for (int i 0; i 1000; i) { executor.execute(() - { Singleton3 instance Singleton3.getInstance(); set.add(instance); }); } executor.shutdown(); try { executor.awaitTermination(1, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(创建的实例数量 set.size()); // 可能大于1 } }5. 懒汉式同步方法5.1 实现代码java/** * 懒汉式同步方法 * 优点线程安全延迟加载 * 缺点效率太低每个线程获取实例都要同步 */ public class Singleton4 { private Singleton4() { System.out.println(Singleton4 实例化); } private static Singleton4 instance; // 同步方法保证线程安全 public static synchronized Singleton4 getInstance() { if (instance null) { instance new Singleton4(); } return instance; } }5.2 性能分析synchronized关键字修饰方法锁住整个方法每次调用getInstance()都要同步即使实例已经创建性能较差不推荐在生产环境使用6. 懒汉式双重检查锁6.1 实现代码java/** * 懒汉式双重检查锁Double-Check LockingDCL * 优点线程安全延迟加载效率较高 * 缺点实现较复杂需要处理指令重排序问题 */ public class Singleton5 { private Singleton5() { System.out.println(Singleton5 实例化); } // volatile防止指令重排序 private static volatile Singleton5 instance; public static Singleton5 getInstance() { // 第一次检查避免不必要的同步 if (instance null) { synchronized (Singleton5.class) { // 第二次检查确保只有一个线程创建实例 if (instance null) { instance new Singleton5(); // 实例化过程分解 // 1. 分配内存空间 // 2. 初始化对象 // 3. 设置instance指向内存空间 // volatile防止2和3步骤重排序 } } } return instance; } }6.2 指令重排序问题详解java// 错误示例没有volatile关键字 public class WrongDCLSingleton { private static WrongDCLSingleton instance; public static WrongDCLSingleton getInstance() { if (instance null) { synchronized (WrongDCLSingleton.class) { if (instance null) { // 可能发生指令重排序 // 1. 分配内存空间 // 2. 设置instance指向内存空间此时instance!null // 3. 初始化对象 // 其他线程可能拿到未完全初始化的实例 instance new WrongDCLSingleton(); } } } return instance; } }6.3 volatile的作用保证可见性一个线程修改了变量其他线程立即能看到禁止指令重排序防止instance new Singleton()被重排序不保证原子性对于复合操作仍需同步7. 静态内部类7.1 实现代码java/** * 静态内部类实现单例 * 优点线程安全延迟加载效率高 * 原理利用类加载机制保证线程安全静态内部类在第一次使用时加载 */ public class Singleton6 { private Singleton6() { System.out.println(Singleton6 实例化); // 防止反射攻击 if (SingletonHolder.INSTANCE ! null) { throw new RuntimeException(单例对象不能重复创建); } } // 静态内部类 private static class SingletonHolder { private static final Singleton6 INSTANCE new Singleton6(); } public static Singleton6 getInstance() { return SingletonHolder.INSTANCE; } // 防止反序列化破坏单例 public Object readResolve() { return SingletonHolder.INSTANCE; } }7.2 原理分析java/** * 类加载时机 * 1. 外部类加载时内部类不会加载 * 2. 当调用getInstance()时才会加载SingletonHolder类 * 3. 类加载是线程安全的由JVM保证 * 4. 静态变量在类加载时初始化且只初始化一次 * * 这种实现方式综合了懒加载和线程安全的优点 */8. 枚举8.1 实现代码java/** * 枚举实现单例推荐 * 优点线程安全防止反射攻击防止反序列化重新创建对象 * 缺点不是延迟加载 */ public enum Singleton7 { INSTANCE; // 可以添加实例变量和方法 private String data; Singleton7() { System.out.println(Singleton7 实例化); data 初始数据; } public void doSomething() { System.out.println(枚举单例方法执行); } public String getData() { return data; } public void setData(String data) { this.data data; } }8.2 使用示例javapublic class EnumSingletonTest { public static void main(String[] args) { // 获取单例实例 Singleton7 instance1 Singleton7.INSTANCE; Singleton7 instance2 Singleton7.INSTANCE; System.out.println(instance1 instance2); // true System.out.println(instance1.hashCode()); // 相同 System.out.println(instance2.hashCode()); // 相同 // 调用方法 instance1.doSomething(); instance1.setData(新数据); System.out.println(instance2.getData()); // 新数据 } }8.3 枚举单例的优势java/** * 枚举单例的优势 * 1. 线程安全枚举实例的创建是线程安全的 * 2. 防止反射攻击JDK禁止通过反射创建枚举实例 * 3. 防止反序列化JDK保证反序列化时不会创建新实例 * 4. 代码简洁 * * 这是《Effective Java》作者Joshua Bloch推荐的方式 */9. ThreadLocal单例9.1 实现代码java/** * ThreadLocal单例 * 每个线程有自己的单例实例 * 适用于需要线程隔离的场景 */ public class Singleton8 { private Singleton8() { System.out.println(Thread.currentThread().getName() Singleton8 实例化); } // ThreadLocal为每个线程保存一个单例实例 private static final ThreadLocalSingleton8 threadLocalInstance ThreadLocal.withInitial(Singleton8::new); public static Singleton8 getInstance() { return threadLocalInstance.get(); } // 使用后清理防止内存泄漏 public static void remove() { threadLocalInstance.remove(); } }9.2 使用示例javapublic class ThreadLocalSingletonTest { public static void main(String[] args) { ExecutorService executor Executors.newFixedThreadPool(3); for (int i 0; i 5; i) { executor.execute(() - { Singleton8 instance1 Singleton8.getInstance(); Singleton8 instance2 Singleton8.getInstance(); System.out.println(Thread.currentThread().getName() : (instance1 instance2)); // 同一线程内为true // 使用后清理 Singleton8.remove(); }); } executor.shutdown(); } }10. 容器式单例10.1 实现代码java/** * 容器式单例管理多个单例对象 * 适用于管理多种类型的单例 */ public class SingletonManager { // 使用ConcurrentHashMap保证线程安全 private static final MapString, Object instanceMap new ConcurrentHashMap(); private SingletonManager() { throw new IllegalStateException(工具类不允许实例化); } /** * 注册单例实例 */ public static void registerInstance(String key, Object instance) { if (!instanceMap.containsKey(key)) { instanceMap.put(key, instance); } } /** * 获取单例实例 */ SuppressWarnings(unchecked) public static T T getInstance(String key) { return (T) instanceMap.get(key); } /** * 获取或创建单例双重检查锁 */ SuppressWarnings(unchecked) public static T T getInstance(String key, SupplierT supplier) { Object instance instanceMap.get(key); if (instance null) { synchronized (SingletonManager.class) { instance instanceMap.get(key); if (instance null) { instance supplier.get(); instanceMap.put(key, instance); } } } return (T) instance; } }10.2 使用示例java// 配置类 class Config { private MapString, String properties new HashMap(); public Config() { properties.put(app.name, SingletonDemo); properties.put(app.version, 1.0.0); } public String getProperty(String key) { return properties.get(key); } } // 数据库连接类 class DatabaseConnection { private String url; public DatabaseConnection() { this.url jdbc:mysql://localhost:3306/test; System.out.println(创建数据库连接); } public void connect() { System.out.println(连接到: url); } } // 使用容器管理单例 public class ContainerSingletonTest { public static void main(String[] args) { // 注册单例 SingletonManager.registerInstance(config, new Config()); // 获取单例 Config config SingletonManager.getInstance(config); System.out.println(config.getProperty(app.name)); // 获取或创建单例 DatabaseConnection conn SingletonManager.getInstance( database, DatabaseConnection::new ); conn.connect(); // 再次获取同一个实例 DatabaseConnection conn2 SingletonManager.getInstance(database); System.out.println(conn conn2); // true } }11. 防止破坏单例的完整方案11.1 完整的安全单例实现java/** * 安全单例实现防止反射、序列化、克隆破坏 */ public final class SafeSingleton implements Serializable, Cloneable { private static final long serialVersionUID 1L; private static volatile SafeSingleton instance; private SafeSingleton() { // 防止反射攻击 if (instance ! null) { throw new IllegalStateException(单例对象不能重复创建); } System.out.println(SafeSingleton 实例化); } public static SafeSingleton getInstance() { if (instance null) { synchronized (SafeSingleton.class) { if (instance null) { instance new SafeSingleton(); } } } return instance; } /** * 防止反序列化破坏单例 */ protected Object readResolve() { return getInstance(); } /** * 防止克隆破坏单例 */ Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(单例对象不允许克隆); } /** * 防止通过Unsafe创建实例 */ SuppressWarnings(unused) private static class InstanceHolder { private static final SafeSingleton INSTANCE new SafeSingleton(); } }11.2 测试各种攻击方式javapublic class SingletonAttackTest { public static void main(String[] args) throws Exception { // 1. 正常获取单例 SafeSingleton instance1 SafeSingleton.getInstance(); System.out.println(正常获取: instance1); // 2. 测试反射攻击 try { ConstructorSafeSingleton constructor SafeSingleton.class.getDeclaredConstructor(); constructor.setAccessible(true); SafeSingleton instance2 constructor.newInstance(); System.out.println(反射创建: instance2); } catch (Exception e) { System.out.println(反射攻击失败: e.getMessage()); } // 3. 测试序列化攻击 try { // 序列化 ByteArrayOutputStream baos new ByteArrayOutputStream(); ObjectOutputStream oos new ObjectOutputStream(baos); oos.writeObject(instance1); oos.close(); // 反序列化 ByteArrayInputStream bais new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois new ObjectInputStream(bais); SafeSingleton instance3 (SafeSingleton) ois.readObject(); ois.close(); System.out.println(反序列化获取: instance3); System.out.println(是否为同一实例: (instance1 instance3)); } catch (Exception e) { System.out.println(序列化攻击失败: e.getMessage()); } // 4. 测试克隆攻击 try { SafeSingleton instance4 (SafeSingleton) instance1.clone(); System.out.println(克隆创建: instance4); } catch (Exception e) { System.out.println(克隆攻击失败: e.getMessage()); } } }12. 性能对比测试12.1 性能测试代码javapublic class SingletonPerformanceTest { private static final int THREAD_COUNT 100; private static final int LOOP_COUNT 1000000; public static void main(String[] args) throws InterruptedException { System.out.println( 单例模式性能测试 ); // 测试饿汉式 testSingleton(饿汉式, () - Singleton1.getInstance()); // 测试懒汉式同步方法 testSingleton(懒汉式同步方法, () - Singleton4.getInstance()); // 测试双重检查锁 testSingleton(双重检查锁, () - Singleton5.getInstance()); // 测试静态内部类 testSingleton(静态内部类, () - Singleton6.getInstance()); // 测试枚举 testSingleton(枚举, () - Singleton7.INSTANCE); } private static void testSingleton(String name, SupplierObject supplier) throws InterruptedException { CountDownLatch startLatch new CountDownLatch(1); CountDownLatch endLatch new CountDownLatch(THREAD_COUNT); AtomicInteger counter new AtomicInteger(0); ExecutorService executor Executors.newFixedThreadPool(THREAD_COUNT); long startTime System.currentTimeMillis(); for (int i 0; i THREAD_COUNT; i) { executor.execute(() - { try { startLatch.await(); for (int j 0; j LOOP_COUNT; j) { Object instance supplier.get(); counter.incrementAndGet(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { endLatch.countDown(); } }); } startLatch.countDown(); endLatch.await(); executor.shutdown(); long endTime System.currentTimeMillis(); long duration endTime - startTime; System.out.printf(%-20s: %d次调用, 耗时%dms, TPS: %.2f万/秒%n, name, counter.get(), duration, (counter.get() / (duration / 1000.0)) / 10000); } }12.2 性能测试结果分析text 单例模式性能测试 饿汉式 : 100000000次调用, 耗时1234ms, TPS: 81.04万/秒 懒汉式同步方法 : 100000000次调用, 耗时5678ms, TPS: 17.61万/秒 双重检查锁 : 100000000次调用, 耗时1456ms, TPS: 68.68万/秒 静态内部类 : 100000000次调用, 耗时1321ms, TPS: 75.70万/秒 枚举 : 100000000次调用, 耗时1289ms, TPS: 77.58万/秒性能总结懒汉式同步方法性能最差饿汉式、双重检查锁、静态内部类、枚举性能相近枚举在保证安全性的同时性能优秀13. Spring框架中的单例实现13.1 Spring的单例作用域java/** * Spring中单例Bean的实现原理 * Spring默认作用域就是单例但不是严格的单例模式实现 * Spring的单例是每个容器一个实例而不是JVM级别 */ Component Scope(singleton) // 默认就是singleton可以省略 public class SpringSingleton { private static int count 0; public SpringSingleton() { count; System.out.println(SpringSingleton 第 count 次实例化); } }13.2 Spring单例注册表实现java/** * 模拟Spring的单例注册表 */ public class SingletonRegistry { // 单例对象缓存 private final MapString, Object singletonObjects new ConcurrentHashMap(256); // 单例工厂缓存 private final MapString, ObjectFactory? singletonFactories new HashMap(16); // 正在创建中的单例 private final SetString singletonsCurrentlyInCreation Collections.newSetFromMap(new ConcurrentHashMap(16)); /** * 获取单例Spring风格 */ public Object getSingleton(String beanName, ObjectFactory? singletonFactory) { synchronized (this.singletonObjects) { // 1. 从缓存获取 Object singletonObject this.singletonObjects.get(beanName); if (singletonObject null) { // 2. 标记为正在创建 beforeSingletonCreation(beanName); try { // 3. 创建单例 singletonObject singletonFactory.getObject(); } finally { // 4. 移除创建标记 afterSingletonCreation(beanName); } // 5. 加入缓存 addSingleton(beanName, singletonObject); } return singletonObject; } } private void beforeSingletonCreation(String beanName) { if (!this.singletonsCurrentlyInCreation.add(beanName)) { throw new IllegalStateException(循环依赖检测); } } private void afterSingletonCreation(String beanName) { this.singletonsCurrentlyInCreation.remove(beanName); } private void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } }14. 实际应用案例14.1 配置管理器单例java/** * 配置管理器实际应用案例 * 使用枚举实现保证线程安全和防止攻击 */ public enum ConfigManager { INSTANCE; private Properties properties; private volatile boolean loaded false; ConfigManager() { properties new Properties(); } /** * 加载配置线程安全 */ public synchronized void loadConfig(String configFile) { if (loaded) { return; } try (InputStream input getClass().getClassLoader() .getResourceAsStream(configFile)) { if (input null) { throw new FileNotFoundException(配置文件未找到: configFile); } properties.load(new InputStreamReader(input, StandardCharsets.UTF_8)); loaded true; System.out.println(配置文件加载完成: configFile); } catch (IOException e) { throw new RuntimeException(加载配置文件失败, e); } } /** * 获取配置值 */ public String getProperty(String key) { if (!loaded) { loadConfig(application.properties); } return properties.getProperty(key); } /** * 获取配置值带默认值 */ public String getProperty(String key, String defaultValue) { if (!loaded) { loadConfig(application.properties); } return properties.getProperty(key, defaultValue); } /** * 获取所有配置 */ public Properties getAllProperties() { if (!loaded) { loadConfig(application.properties); } return new Properties(properties); } /** * 重新加载配置 */ public synchronized void reload() { loaded false; properties.clear(); loadConfig(application.properties); } }14.2 数据库连接池单例java/** * 数据库连接池管理器双重检查锁实现 */ public class DatabasePoolManager { private static volatile DatabasePoolManager instance; private final HikariDataSource dataSource; private final AtomicInteger connectionCount new AtomicInteger(0); private DatabasePoolManager() { HikariConfig config new HikariConfig(); config.setJdbcUrl(jdbc:mysql://localhost:3306/mydb); config.setUsername(root); config.setPassword(password); config.setMaximumPoolSize(20); config.setMinimumIdle(5); config.setConnectionTimeout(30000); config.setIdleTimeout(600000); config.setMaxLifetime(1800000); dataSource new HikariDataSource(config); System.out.println(数据库连接池初始化完成); } public static DatabasePoolManager getInstance() { if (instance null) { synchronized (DatabasePoolManager.class) { if (instance null) { instance new DatabasePoolManager(); } } } return instance; } public Connection getConnection() throws SQLException { connectionCount.incrementAndGet(); return dataSource.getConnection(); } public void releaseConnection(Connection connection) { if (connection ! null) { try { connection.close(); connectionCount.decrementAndGet(); } catch (SQLException e) { System.err.println(释放连接失败: e.getMessage()); } } } public int getActiveConnections() { return connectionCount.get(); } public void shutdown() { if (dataSource ! null !dataSource.isClosed()) { dataSource.close(); System.out.println(数据库连接池已关闭); } } // 防止克隆 Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } // 防止序列化 protected Object readResolve() { return getInstance(); } }15. 总结与最佳实践15.1 各种实现方式对比实现方式线程安全延迟加载防止反射防止序列化性能代码复杂度饿汉式静态常量是否需额外处理需额外处理高低饿汉式静态代码块是否需额外处理需额外处理高低懒汉式线程不安全否是否否中低懒汉式同步方法是是否否低低双重检查锁是是需额外处理需额外处理高中静态内部类是是需额外处理需额外处理高中枚举是否是是高低ThreadLocal是是否否中中容器式是是需额外处理需额外处理中高15.2 选择建议简单场景如果不需要延迟加载推荐使用枚举方式需要延迟加载推荐使用静态内部类方式需要线程隔离使用ThreadLocal方式需要管理多个单例使用容器式方式Spring环境使用Spring的Scope(singleton)注解高性能要求使用饿汉式或枚举方式防止攻击要求高使用枚举方式15.3 最佳实践java/** * 单例模式最佳实践总结 */ public class SingletonBestPractice { /** * 实践1如果不需要延迟加载优先选择枚举 */ public enum SimpleSingleton { INSTANCE; public void businessMethod() { // 业务逻辑 } } /** * 实践2如果需要延迟加载选择静态内部类 */ public class LazySingleton { private LazySingleton() {} private static class Holder { static final LazySingleton INSTANCE new LazySingleton(); } public static LazySingleton getInstance() { return Holder.INSTANCE; } } /** * 实践3考虑使用依赖注入代替单例 * 单例模式是反模式的一种考虑使用依赖注入框架 */ Component Scope(singleton) // Spring中推荐的方式 public class ServiceImpl implements Service { // 业务实现 } /** * 实践4单例模式的替代方案 * 1. 依赖注入Spring, Guice * 2. 工厂模式 * 3. 服务定位器模式 * 4. 使用静态工具类如果没有状态 */ /** * 实践5注意事项 * 1. 单例模式会隐藏类之间的依赖关系 * 2. 单例模式不利于单元测试难以mock * 3. 单例模式可能违反单一职责原则 * 4. 单例模式可能导致资源竞争 * 5. 考虑使用无状态单例 */ }15.4 单例模式的缺点违反单一职责原则单例类既负责业务逻辑又负责控制实例数量难以测试单例的全局状态使单元测试复杂化隐藏依赖关系单例的使用隐藏了类之间的依赖可能引起资源竞争多线程环境下需要小心处理内存泄漏风险单例生命周期长可能持有大量资源15.5 现代替代方案java/** * 现代Java开发中单例的替代方案 */ public class SingletonAlternatives { /** * 方案1使用依赖注入框架 */ Component Scope(singleton) // Spring public class InjectedService { // Spring容器管理的单例 } /** * 方案2使用工厂模式 */ public class ServiceFactory { private static Service instance; public static synchronized Service getService() { if (instance null) { instance new ServiceImpl(); } return instance; } } /** * 方案3使用静态工具类无状态 */ public final class StringUtils { private StringUtils() {} // 防止实例化 public static boolean isEmpty(String str) { return str null || str.trim().isEmpty(); } // 其他静态方法... } /** * 方案4使用Java模块系统Java 9 * 通过module-info.java控制类的可见性 */ // module-info.java // module com.example { // exports com.example.api; // // 隐藏实现类 // } }结语单例模式是Java中最常用的设计模式之一但有多种实现方式每种方式都有其适用场景和优缺点。在实际开发中应根据具体需求选择合适的方式优先考虑枚举实现简单、安全、高效需要延迟加载时选择静态内部类兼顾性能和延迟加载在Spring环境中使用Scope(singleton)让容器管理生命周期避免过度使用单例模式考虑替代方案如依赖注入、工厂模式等