Java中基于内部类的单例懒加载原理及LazyHolder加载时机问询
代码示例
单例实现类
class Singleton { // 用于懒加载的私有静态内部类 private static class LazyHolder { private static Singleton singleton = new Singleton(); } public static Singleton getSingleton() { return LazyHolder.singleton; } }
测试主类
class Main { // 修正原代码缺失的void关键字 public static void main(String[] args) { Singleton s = Singleton.getSingleton(); } }
核心疑问
根据所学内容,private static Singleton singleton实例会在Singleton s = Singleton.getSingleton()语句执行时创建,但由于singleton是静态属性,我原本以为它会在LazyHolder类定义时就被创建。因此想明确:LazyHolder类实际何时被加载?是在Singleton类加载时(因为它是Singleton的内部类),还是在调用Singleton.getSingleton()方法时?同时需要了解运行时的具体执行过程。
加载时机与执行过程解析
Singleton类的加载逻辑:当JVM首次遇到Singleton类的引用(比如Main类中调用getSingleton())时,会加载Singleton类,但此时不会自动加载它的静态内部类LazyHolder。Java规范明确规定:静态内部类属于外部类的“嵌套类”,不会随着外部类的加载而被加载,只有当它被主动引用时才会触发加载流程。LazyHolder类的触发节点:当调用Singleton.getSingleton()方法时,方法体内直接引用了LazyHolder.singleton,这属于对LazyHolder类的主动引用,此时JVM才会启动LazyHolder类的加载与初始化流程。singleton实例的创建逻辑:在LazyHolder类的初始化阶段,JVM会按顺序执行类的静态成员赋值语句,也就是private static Singleton singleton = new Singleton();,此时才真正创建Singleton的实例。这个初始化过程是线程安全的——JVM在类初始化阶段会保证静态成员的初始化操作是原子性的,且只会执行一次,这也是这种单例模式天生线程安全的核心原因。完整运行流程:
- 启动程序,JVM加载
Main类; - 执行
main方法中的Singleton s = Singleton.getSingleton();,首次引用Singleton类,JVM加载Singleton类; - 进入
getSingleton()方法,代码访问LazyHolder.singleton,触发LazyHolder类的加载与初始化; LazyHolder初始化时,创建Singleton实例并赋值给singleton静态变量;- 将
singleton实例返回,赋值给Main类中的变量s。
- 启动程序,JVM加载
内容的提问来源于stack exchange,提问作者idash

