静态内部类单例的核心是利用JVM类加载机制实现懒加载与线程安全:外部类加载时不初始化内部类,仅首次调用getInstance()时触发Holder类初始化,由JVM保证<clinit>执行的原子性与唯一性,无需synchronized或volatile,兼具高性能、简洁性与可靠性。

Java 中用 static 实现静态内部类单例,核心是利用 JVM 类加载机制的线程安全性和延迟加载特性——外部类加载时,静态内部类不会被立即加载,只有首次调用 getInstance() 时才触发内部类初始化,从而安全地创建唯一实例。
静态内部类单例的标准写法
这是最推荐的单例实现方式之一,兼顾懒加载、线程安全和简洁性:
public class Singleton {
// 私有构造防止外部实例化
private Singleton() {}
// 静态内部类,持有单例实例
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
// 全局访问点,调用时才加载 Holder 类
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
关键点:
- JVM 保证类的静态成员在类初始化阶段才被赋值,且该过程天然线程安全
-
Holder类仅在getInstance()第一次执行时被加载,实现真正的懒加载 - 无需
synchronized或双重检查锁,无性能开销
为什么不能把 INSTANCE 直接放在外部类里
如果写成这样:
立即学习“Java免费学习笔记(深入)”;
public class Singleton {
private static final Singleton INSTANCE = new Singleton(); // ❌ 饿汉式,非懒加载
private Singleton() {}
public static Singleton getInstance() { return INSTANCE; }
}
会导致类加载时就创建实例,违背“按需创建”的初衷。而静态内部类把初始化时机推迟到第一次调用方法时,更符合懒加载语义。
注意事项与常见误区
使用时需注意以下几点:
- 构造器必须私有,否则可通过
new Singleton()绕过单例控制 - 内部类名(如
Holder)无特殊要求,但建议语义清晰、不暴露 - 该方式不防反射攻击(可通过反射调用私有构造器),如需更强防护,可在构造器中加标志位校验
- 序列化场景下,若单例类实现
Serializable,需添加readResolve()方法防止反序列化破坏单例
对比其他单例实现
相比常见方案:
- 比饿汉式更节省资源(延迟初始化)
- 比双重检查锁(DCL)更简洁、无 volatile 和同步开销
- 比枚举单例少了可扩展性(如需继承或实现接口时静态内部类更灵活)
静态内部类单例是平衡安全性、性能与可读性的优选方案,适合绝大多数业务场景。


















