静态内部类实现单例的核心是JVM类加载机制保障懒加载与线程安全:外部类构造私有、内部类用static修饰、实例字段为static final;首次调用getInstance时才加载SingletonHolder并初始化INSTANCE,JVM保证仅执行一次。

用静态内部类实现单例,核心是靠 JVM 类加载机制自动保障线程安全和懒加载——不用加锁、不依赖 volatile、也不需要双重检查,写法简洁,运行高效。
关键结构要写对
必须满足三个硬性条件,缺一不可:
- 外部类构造方法设为 private,禁止外部 new
- 内部类用 static 修饰(不是普通内部类),否则会隐式持外部类引用,且无法在静态方法中访问
- 内部类中声明的实例字段必须是 static final(或至少 static,配合私有构造防反射)
标准写法示例
这是可直接复制使用的模板:
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
调用 Singleton.getInstance() 时,JVM 才首次加载 SingletonHolder 类,并执行其 (类初始化方法),完成实例创建。这个过程由 JVM 保证只执行一次,天然线程安全。
为什么它既懒加载又线程安全
原因全在 JVM 规范里:
-
懒加载:外部类
Singleton加载时,SingletonHolder完全不触发;只有第一次调用getInstance()中引用到它,才启动加载与初始化 -
线程安全:
是 JVM 级同步操作,类加载器会自动加锁,确保多线程下该内部类最多初始化一次,实例只会被创建一次
需要注意的边界情况
看似简单,但几个细节容易踩坑:
- 如果单例初始化需要参数(比如读配置、传 context),静态内部类方式无法直接支持,得改用枚举或带参工厂
- 反序列化可能绕过构造函数重建对象,如需防御,可在外部类添加
readResolve()方法返回INSTANCE - 别在外部类的静态字段初始化语句里提前引用
SingletonHolder,例如static Object o = new SingletonHolder();,这会破坏懒加载时机










