GeezerVison is showing notes.kamacoder.com — 单例模式|大厂面试题|Java高频面试题|懒汉式、饿汉式、双重检查锁、静态内部类
# 单例模式
# 简要回答
- 单例设计模式是一种确保一个类在运行期间只有一个实例,提供一个全局访问点来访问该实例的创建型模式。核心特点如下:
- 私有化构造方法,防止外部通过new关键字直接实例化对象。
- 类内部自行创建一个私有的静态变量,保存该类的唯一实例。
- 提供公共静态方法,给使用者提供调用方法,返回唯一实例。
- 单例模式适用于资源独占、全局统一管理的场景,可以避免一个全局使用的类被频繁创建与销毁,耗费系统资源。
# 详细回答
# 知识图解
- 单例模式结构图

- 双重检查锁

# 使用场景
- 单例模式适用于类只能有一个实例且客户可以从一个众所周知的访问点访问它的场景,频繁创建与销毁的对象可以通过单例模式提高性能,经常使用且实例化复杂的对象可以通过单例模式避免重复创建,需要控制共享资源时可以使用单例模式方便通信。
- 常见的应用场景如下:
- 资源密集型对象的创建:创建数据库连接池、线程池时可以使用单例模式,避免重复创建浪费系统资源,单例模式可以保证全局仅有一个池实例,进行统一管理连接、线程。
- 系统的全局配置:数据库地址、APIkey等配置资源可以通过单例模式封装,能够保证所有模块获取的配置资源一致,避免重复读取。
- 工具类:例如日志管理工具类和缓存工具类,需要全局统一的入口操作资源,使用单例模式可以避免多实例导致的日志混乱、缓存不一致等问题。
- 硬件操作:硬件资源唯一,单例模式可以保证同一时间只有一个实例操作硬件,避免冲突。
# 知识扩展
- 面试官可能追问:
- Q1:怎么选择单例模式的实现方式?
- 根据业务的实际需求选择,如果不需要实现懒加载,可以使用饿汉式简单实现,如果需要防止反射和序列化则使用枚举方式实现;
- 需要懒加载实现单例模式时,对懒汉式加锁可以以性能较低的方式实现,还可以使用静态内部类实现;如果需要传参初始化,可以使用双重检查锁(DCL)实现单例模式。
- Q2:为什么双重检查锁需要加 volatile?
- instance=new DCLSingleton()并非原子操作,会被拆分为3步:①分配内存;②初始化实例;③给 instance赋值。JVM中可能发生指令重排(如先执行③再执行②),导致多线程下某个线程获取到 “半初始化” 的实例(instance 不为 null,但对象未初始化完成)。volatile关键字可禁止指令重排,保证实例创建的原子性。
- Q3:反射 / 序列化会破坏单例吗?如何解决?
- 反射破坏:通过Constructor.setAccessible(true) 可强制调用私有构造方法,创建多个实例;使用饿汉式 / 静态内部类可在构造方法中加判断(若 instance 不为 null 则抛异常);枚举天然防反射,如果反射创建枚举会抛 IllegalArgumentException异常。
- 序列化破坏:序列化单例对象后反序列化,会生成新实例;可以通过重写readResolve() 方法解决,返回已有的单例实例;枚举天然防序列化破坏。