1. 单例模式为什么它是GoF设计模式中的常青树第一次接触单例模式是在2013年参与银行交易系统开发时。当时需要设计一个全局的交易流水号生成器团队里一位资深工程师坚决要求使用单例模式实现。他当时说的一句话让我记忆犹新这个类要是能被实例化两次咱们的流水号就全乱套了。这句话道破了单例模式的核心价值——确保一个类只有一个实例并提供一个全局访问点。在GoFGang of Four提出的23种设计模式中单例模式可能是应用最广泛的一个。从操作系统中的任务管理器到数据库连接池再到各种配置管理类单例模式无处不在。特别是在需要控制资源访问或维护全局状态的场景中它展现出了不可替代的价值。关键提示单例模式不是简单的把构造函数设为private它涉及线程安全、序列化安全、反射防御等多维度考量。很多面试中所谓的手写单例问题其实是在考察你对这些深层次问题的理解。2. 单例模式的核心实现方式解析2.1 饿汉式简单粗暴的线程安全方案饿汉式单例是我在Android系统开发中最常用的实现方式。它的特点是在类加载时就完成实例化代码如下public class BankTransactionManager { private static final BankTransactionManager instance new BankTransactionManager(); private BankTransactionManager() { // 防止反射攻击 if (instance ! null) { throw new RuntimeException(Use getInstance() method to get the single instance.); } } public static BankTransactionManager getInstance() { return instance; } }这种实现方式的优势非常明显绝对线程安全实例在类加载时创建JVM保证类加载过程的线程安全性代码简洁没有复杂的同步逻辑执行效率高获取实例时直接返回无任何性能开销但它的缺点同样突出如果实例化过程耗时较长会导致类加载变慢即使程序从未使用该单例也会创建实例可能造成资源浪费在金融领域的交易系统中我推荐使用饿汉式。因为交易核心组件通常都是启动时就必须初始化的而且对线程安全有极高要求。比如银行的日终批处理控制器就必须使用这种实现方式。2.2 懒汉式按需加载的艺术懒汉式的核心思想是延迟实例化直到真正需要时才创建实例。基础实现如下public class Logger { private static Logger instance; private Logger() {} public static synchronized Logger getInstance() { if (instance null) { instance new Logger(); } return instance; } }这种实现解决了饿汉式的资源浪费问题但引入了新的挑战同步锁开销每次获取实例都要经过同步锁性能较差指令重排序风险在未正确同步的情况下可能出现部分初始化的对象我在实际项目中见过一个典型的错误案例某电商平台的购物车服务使用了未同步的懒汉式单例在大促期间出现了多个购物车实例导致用户看到的商品数量不一致。这就是典型的线程安全问题。2.3 双重校验锁性能与安全的平衡点结合饿汉式的线程安全优势和懒汉式的延迟加载特性双重校验锁模式应运而生public class DatabaseConnectionPool { private static volatile DatabaseConnectionPool instance; private DatabaseConnectionPool() { // 初始化连接池 } public static DatabaseConnectionPool getInstance() { if (instance null) { synchronized (DatabaseConnectionPool.class) { if (instance null) { instance new DatabaseConnectionPool(); } } } return instance; } }这里有几个关键点需要注意volatile关键字防止指令重排序确保所有线程看到的instance状态一致双重检查外层检查避免不必要的同步内层检查确保单例延迟初始化只有在第一次调用getInstance()时才创建实例在数据库连接池这类资源密集型场景中双重校验锁是最佳选择。我曾经优化过一个社交平台的数据库访问层将简单的懒汉式改为双重校验锁后QPS提升了约30%。3. 单例模式的进阶话题与陷阱防范3.1 反射攻击与防御策略即使我们将构造函数设为private反射仍然可以破坏单例ConstructorBankTransactionManager constructor BankTransactionManager.class.getDeclaredConstructor(); constructor.setAccessible(true); BankTransactionManager instance2 constructor.newInstance();防御方法是在构造函数中添加检查private BankTransactionManager() { if (instance ! null) { throw new RuntimeException(Use getInstance() method to get the single instance.); } }3.2 序列化与反序列化问题如果单例类实现了Serializable接口反序列化时会创建新实例。解决方法protected Object readResolve() { return getInstance(); }3.3 枚举单例最安全的实现方式从Java 1.5开始枚举类型成为了实现单例的最佳实践public enum SystemConfig { INSTANCE; private String appName; public String getAppName() { return appName; } public void setAppName(String appName) { this.appName appName; } }枚举单例的优势绝对防止多次实例化包括反射攻击自动处理序列化问题代码极其简洁在Android开发中我常用枚举单例来管理应用全局配置。比如public enum AppSettings { INSTANCE; private boolean darkMode; private String language; // getters and setters }4. 单例模式的典型应用场景与误用警示4.1 适用场景分析配置管理类如系统参数、应用设置等资源管理器数据库连接池、线程池等工具类日志记录器、性能监控器等状态管理用户会话信息、全局计数器等在银行核心系统中以下组件通常采用单例模式交易流水号生成器汇率转换服务风控规则引擎日终批处理控制器4.2 常见误用与反模式滥用单例导致代码耦合将本应作为参数传递的对象改为单例获取破坏代码的可测试性持有Context引用导致内存泄漏在Android中单例持有Activity引用会导致Activity无法回收过度依赖全局状态使程序行为难以预测和理解我曾经重构过一个电商系统发现他们竟然将购物车做成了单例这直接导致了不同用户看到相同的购物内容。正确的做法应该是每个用户会话拥有独立的购物车实例。4.3 单例模式在框架中的应用实例Spring框架默认情况下Spring管理的Bean都是单例作用域Android系统LayoutInflater、WindowManager等系统服务Java标准库Runtime.getRuntime()方法返回的就是单例在框架设计中单例模式通常与工厂模式结合使用。比如Spring的ApplicationContext在内部就维护了一个单例的Bean工厂。5. 单例模式的替代方案与演进思考5.1 依赖注入 vs 单例现代框架更推荐使用依赖注入DI来管理对象生命周期public class PaymentService { private final TransactionLogger logger; Inject public PaymentService(TransactionLogger logger) { this.logger logger; } }与单例相比DI的优势在于更易于单元测试明确的生命周期管理更好的解耦5.2 对象池模式对于创建成本高的对象对象池可能是比单例更好的选择。比如数据库连接池就管理着多个连接实例而非单一实例。5.3 多例模式Multiton当需要有限数量的实例时可以使用多例模式。比如连接池通常就采用这种模式。在最近的一个物联网项目中我们为每种设备类型创建了一个管理器的多例既控制了实例数量又避免了单例的局限性。6. 单例模式面试深度剖析6.1 高频面试题解析如何破坏单例模式如何防御破坏方式反射、序列化、克隆防御策略枚举实现、readResolve方法、clone方法重写双重校验锁为什么要加volatile防止指令重排序导致的部分初始化问题保证变量的可见性单例模式的优缺点是什么优点控制实例数量、全局访问点、节省资源缺点难以测试、隐藏依赖、生命周期管理困难6.2 手写单例的考察要点面试官让你手写单例时实际上在考察对线程安全的理解深度对JVM内存模型的掌握程度对设计模式应用场景的判断能力我建议按照这个顺序回答先给出枚举实现最安全再展示双重校验锁实现考察重点最后讨论其他实现的优缺点6.3 实际案例分析与解决方案曾经有位面试者给出了一个看似完美的单例实现但在讨论环节我问了一个问题如果这个单例的初始化需要依赖外部配置且配置可能变化该如何处理这考察的是对单例模式局限性的认识。正确的思路应该是将可变状态与单例实例分离使用观察者模式监听配置变化或者考虑使用多例模式替代在架构设计中没有放之四海而皆准的模式。单例模式虽然强大但必须根据具体场景谨慎使用。经过多年的实践我发现单例模式最适合那些真正需要全局唯一且无状态的场景。对于有状态的对象或者需要灵活扩展的系统依赖注入往往是更好的选择。
企业数字化 ERP 产品动态
相关推荐
Golang测试框架详解与实践指南 1. Golang测试框架深度解析 Go语言内置的testing包是每个Golang开发者必须掌握的核心工具。这个轻量级测试框架虽然看似简单,但通过合理使用可以构建完整的测试体系。不同于其他语言的测试框架需要额外安装第三方库,Go的测试工具链开箱即用,这… · 2026/11/3 3:07:37
Golang测试框架详解:从基础到高级实践 1. Golang测试基础概念解析Go语言内置的测试框架是其工具链中最强大的特性之一。与许多其他语言不同,Go不需要额外的测试库或复杂的配置就能开始编写有效的单元测试。测试文件通常与被测试的代码文件放在同一目录下,并以_test.go结尾。测试函数需要遵循特… · 2026/11/3 7:02:32
子域名信息查询与外部资产测绘:从探测到资产清单 做资产梳理这行的朋友大概都有过类似经历:接手一个项目,台账上写着三十来个域名,结果一轮子域名信息查询跑下来,后端暴露出来的入口有三百多个,其中一半以上没人说得清是谁维护的。子域名信息查询这件事听起来只是&quo… · 2026/11/4 13:47:23
d1特种作业操作证怎么转异地?郑州报考避坑指南全解析 d1特种作业操作证怎么转异地?郑州报考避坑指南全解析 怕考不过白交培训费?别急,今天给你讲透d1特种作业操作证怎么转异地,郑州报考避坑指南到底该怎么看,别再被培训机构忽悠了。… · 2026/11/8 2:50:05
特种作业操作证提前网上查询怎么弄?外省证转过来有讲究 特种作业操作证提前网上查询怎么弄?外省证转过来有讲究 之前考的证在外省能不能转过来?这是很多特种作业人员最关心的问题。特别是像你这样在开封从事房建工程的朋友,经常需要跨省作业,证书能否顺利转接直接影响到工作机会和项目承接。别急,接下来我们一… · 2026/11/8 2:50:05
高级电工证要学历吗网上查询怎么查 高级电工证要学历吗网上查询怎么查 实操考试心里没底怕挂科,特别是像咱们这种在施工现场天天跟电打交道的,一个证没拿到,就等于没了工作的“通行证”。今天咱们就聊聊高级电工证要学历吗,网上查询怎么查,还有新乡市政公用工程从业者怎么避坑,怎么补办,… · 2026/11/8 2:50:05
萧山电工证怎么查询 考前押题帮你搞定工地复习难 萧山电工证怎么查询 考前押题帮你搞定工地复习难 工地太忙根本没时间复习考试,这几乎是每个特种作业人员的真实写照。尤其是像电工证这种必须定期复审的证书,一旦到期不及时处理,不仅影响工作进度,还可能面临停工甚至罚款。所以, 萧山电工证怎么查询… · 2026/11/8 2:50:05
电工证有没有必要考试?内部消息告诉你实情 电工证有没有必要考试?内部消息告诉你实情 之前考的证在外省能不能转过来?这是很多在洛阳涧西区转岗或者准备换工作的朋友最关心的问题。别急,我来给你说个 内部消息… · 2026/11/8 2:49:05
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/8 0:00:20
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/8 0:00:20
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/8 0:00:20
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/8 0:00:20
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/8 0:00:20
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/8 0:00:20
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/7 11:25:08
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/7 12:02:18
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/8 1:18:25