单例模式
Singleton — 确保一个类只有一个实例,并提供全局访问点
一句话理解
全局只允许存在一个该类的实例,对外提供统一的获取入口。
解决什么问题
在很多场景中,一个类的对象只需要也只应该有一份:
- 配置中心(全局配置对象)
- 日志管理器
- 线程池、连接池等资源管理类
- 任务调度器
如果任由外界随意 new 对象:
- 资源浪费(重复对象)
- 状态不一致(多份状态难以维护)
怎么写
饿汉式(推荐 —— 简单安全)
类加载时就创建好实例,天然线程安全:
public class Singleton {
// 类加载时就创建唯一实例
private static final Singleton INSTANCE = new Singleton();
// 构造器私有化
private Singleton() {}
// 对外提供获取方法
public static Singleton getInstance() {
return INSTANCE;
}
}三步口诀:构造器私有化 + 静态成员存对象 + 静态方法返回对象。
懒汉式(延迟加载)
需要时才创建,但要处理线程安全问题:
public class Singleton {
private static Singleton instance;
private Singleton() {}
// synchronized 保证线程安全,但性能较差
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}双重检查锁(兼顾性能和安全)
public class Singleton {
// volatile 防止指令重排序
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查(避免不必要的加锁)
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查(防止重复创建)
instance = new Singleton();
}
}
}
return instance;
}
}前端中的单例
在 JavaScript/TypeScript 中,模块本身就是天然的单例:
// config.ts —— 导出的对象就是单例,所有 import 共享同一份
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
}
export default config使用场景
- Spring 中 Bean 的默认作用域就是单例(
@Scope("singleton")) - 数据库连接池(HikariCP)
- Runtime.getRuntime()
- 前端的全局状态管理(Zustand store、Redux store)