静态内部类实现单例的核心是利用jvm类加载机制:外部类加载时不初始化内部类,仅首次调用getinstance()时触发singletonholder类的初始化,由jvm自动加锁确保线程安全与懒加载,无需synchronized或volatile。

Java 中用静态变量实现单例的懒加载,核心是利用 静态内部类 或 双重检查锁定(DCL)+ volatile,而不是直接用普通静态变量——因为普通静态变量会在类加载时就初始化,属于饿汉式,不满足“懒加载”要求。
静态内部类方式(推荐)
这是最简洁、线程安全、天然支持懒加载的方式。外部类加载时,静态内部类不会被加载;只有第一次调用 getInstance() 时,JVM 才会加载并初始化内部类,从而创建单例实例。
- 写法简单,无同步开销,无需 volatile
- 依赖 JVM 类加载机制保证线程安全和懒加载
- 适用于绝大多数场景,是《Effective Java》推荐的方式
public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
双重检查锁定(DCL)+ volatile
适用于需要在 getInstance() 中做额外初始化逻辑(如传参、配置校验)的场景。必须用 volatile 防止指令重排序导致其他线程拿到未构造完成的对象。
- 第一次调用时才创建实例,满足懒加载
- synchronized 块只在首次创建时加锁,后续无性能损耗
- volatile 关键:禁止编译器和 CPU 对 Singleton 构造过程重排序
public class Singleton {
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;
}
}
为什么不能用普通静态变量?
像 private static final Singleton INSTANCE = new Singleton(); 这种写法,类一加载就初始化,属于饿汉式。即使你没调用 getInstance(),只要该类被 ClassLoader 加载(比如被其他类引用),实例就会创建,违背懒加载本意。
- 无法延迟到真正使用时才初始化
- 若构造耗时或依赖外部资源(如数据库连接),可能造成启动慢或失败
- 不满足“按需创建”的懒加载定义
补充说明:枚举单例也支持懒加载
枚举类型的静态字段也是按需初始化的(JVM 规范保证),且天然防止反序列化和反射攻击:
- 语法简洁,线程安全,懒加载,推荐用于强约束场景
- 但扩展性较差(无法继承、无法实现接口中的复杂初始化逻辑)
public enum Singleton {
INSTANCE;
// 可添加方法
public void doSomething() { ... }
}Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











