首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

单例模式:确保唯一实例的设计模式

  • 25-04-24 18:47
  • 3697
  • 10727
juejin.cn

单例模式:确保唯一实例的设计模式

一、模式核心:保证类仅有一个实例并提供全局访问点

在软件开发中,有些类需要确保只有一个实例(如系统配置类、日志管理器),避免因多个实例导致状态混乱或资源浪费。

单例模式(Singleton Pattern) 通过私有化构造方法、持有唯一实例引用、提供静态访问接口,确保一个类在全局范围内只有一个实例,并提供统一的访问入口。核心解决:

  • 实例唯一性:避免创建多个实例消耗资源(如数据库连接池、线程池)。
  • 全局可访问性:为全局提供一个访问点,简化客户端调用。
  • 延迟初始化:支持实例的延迟加载(按需创建),提升系统性能。

核心思想与 UML 类图

单例模式的核心是私有化构造方法,并通过静态方法返回唯一实例。常见实现方式包括:

  • 饿汉式(类加载时立即创建实例)
  • 懒汉式(第一次调用时创建实例,需处理线程安全)

PlantUML Diagram

二、核心实现:三种经典单例模式

1. 饿汉式单例(线程安全,类加载时创建实例)

java
代码解读
复制代码
public class EagerSingleton { // 类加载时立即创建实例(静态变量初始化) private static final EagerSingleton instance = new EagerSingleton(); // 私有化构造方法,防止外部实例化 private EagerSingleton() { System.out.println("创建饿汉式单例实例"); } // 公共访问方法,直接返回实例 public static EagerSingleton getInstance() { return instance; } }

特点:

  • 优点:简单可靠,类加载时完成初始化,天然线程安全。
  • 缺点:无论是否使用都会创建实例,可能浪费内存(适用于实例创建成本低的场景)。

2. 懒汉式单例(线程不安全,延迟创建实例)

java
代码解读
复制代码
public class LazySingleton { private static LazySingleton instance; private LazySingleton() { System.out.println("创建懒汉式单例实例"); } // 未加锁,多线程环境可能创建多个实例 public static LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } }

特点:

  • 优点:延迟加载,节省内存。
  • 缺点:多线程环境下不安全,可能出现多个实例(需改进为线程安全版本)。

3. 线程安全的懒汉式(双重检查锁定,DCL)

java
代码解读
复制代码
public class ThreadSafeSingleton { private static volatile ThreadSafeSingleton instance; // volatile 禁止指令重排 private ThreadSafeSingleton() { System.out.println("创建线程安全懒汉式单例实例"); } public static ThreadSafeSingleton getInstance() { // 第一次检查:实例是否已创建 if (instance == null) { synchronized (ThreadSafeSingleton.class) { // 同步块,保证线程安全 // 第二次检查:防止多个线程同时通过第一次检查 if (instance == null) { instance = new ThreadSafeSingleton(); } } } return instance; } }

关键细节:

  • volatile 关键字:确保 instance 的可见性和禁止指令重排,避免初始化未完成时被其他线程访问。
  • 双重检查(Double-Check Locking):减少同步块的竞争,提升性能。

三、进阶:使用枚举实现单例(推荐方式)

Java 枚举天然支持单例模式,且简洁可靠,自动处理序列化和反射攻击问题。

java
代码解读
复制代码
public enum EnumSingleton { INSTANCE; // 唯一实例 // 附加方法示例 public void doSomething() { System.out.println("枚举单例执行操作"); } }

调用方式:

java
代码解读
复制代码
EnumSingleton.INSTANCE.doSomething(); // 直接通过枚举成员访问

优点:

  • 简洁高效,无需手动处理线程安全和序列化问题。
  • 防止通过反射创建新实例(Enum 类禁止反射攻击)。

四、框架与源码中的单例实践

1. Spring 框架中的单例 Bean

Spring 默认创建的 Bean 是单例的,通过 BeanFactory 管理实例的唯一性。

java
代码解读
复制代码
@Service public class UserService { // Spring 自动创建单例实例 }

2. Log4j 日志管理器

Log4j 的 Logger 类使用单例模式,确保每个类对应的日志记录器唯一。

java
代码解读
复制代码
public class App { private static final Logger logger = Logger.getLogger(App.class); public static void main(String[] args) { logger.info("单例日志记录器"); } }

五、避坑指南:正确使用单例模式的 4 个要点

1. 处理序列化与反序列化攻击

若单例类实现了 Serializable 接口,需添加 readResolve() 方法防止反序列化创建新实例:

java
代码解读
复制代码
protected Object readResolve() { return instance; // 返回现有实例,避免创建新对象 }

2. 防止反射攻击

通过在构造方法中添加校验,禁止通过反射创建多个实例:

java
代码解读
复制代码
private Singleton() { if (instance != null) { throw new IllegalStateException("单例实例已存在"); } // 初始化逻辑 }

3. 避免单例持有长生命周期对象

单例若持有大对象或上下文(如 ApplicationContext),可能导致内存泄漏,需及时释放资源。

4. 谨慎使用延迟加载

懒汉式单例需确保线程安全,否则可能引发 bug;若实例创建成本低,优先使用饿汉式或枚举式。

六、总结:何时该用单例模式?

适用场景核心特征典型案例
全局唯一配置配置信息需要全局共享且唯一系统配置类(ConfigManager)
资源池管理控制资源(如数据库连接)的创建数量数据库连接池、线程池
日志记录器全局共享日志实例Log4j、Logback
避免重复初始化初始化成本高,需保证仅执行一次重量级对象(如缓存管理器)

单例模式通过严格控制实例数量,实现了全局状态的统一管理。下一篇我们将探讨建造者模式,解析如何分步构建复杂对象,敬请期待!

扩展思考:单例模式的缺点

  • 测试困难:单例与测试框架(如 JUnit)的依赖注入冲突,需通过模拟或反射绕过。
  • 违背单一职责原则:单例可能承担业务逻辑与实例管理双重职责,建议将实例管理抽象为独立工厂。
注:本文转载自juejin.cn的AronTing的文章"https://juejin.cn/post/7496335321802981402"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

103
后端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top