Java静态代码块在类初始化阶段仅执行一次,前提是同一类加载器加载且类未卸载;触发条件包括new实例、调用静态方法或访问非final静态字段,多线程下由JVM保证线程安全,类卸载或不同类加载器会导致重复执行。

Java静态代码块在类的初始化阶段执行,且在整个类生命周期内**只执行一次**——前提是该类未被卸载,且由同一个类加载器加载。它不是“类一加载就运行”,也不是“每次 new 都触发”,而是严格绑定在 JVM 类初始化流程中,受内部初始化标记(initialization flag)保护,天然线程安全。
什么情况下真能保证只执行一次?
关键前提是:类由同一个类加载器加载,且未被卸载。JVM 通过类的全限定名 + 加载它的类加载器共同标识一个类;只要这个组合不变,静态代码块就仅执行一次。
- 首次 new 实例、调用 static 方法、访问非 final 静态字段 → 触发初始化,执行静态块
- 后续所有同类操作(哪怕创建 1000 个对象或调用 1 万次 static 方法)→ 不再触发
- 多个线程同时首次触发 → JVM 内部阻塞机制确保仅一个线程执行,其余等待完成
- 父类静态块总在子类之前执行完毕,且各自独立计数(父类只执行一次,子类也只执行一次)
哪些场景会打破“只执行一次”?
看似同一类,实则可能被多次初始化——根本原因在于类加载器隔离:
- 热部署工具(如 Spring Boot DevTools)会启用新类加载器替换旧类 → 新加载器加载的类视为全新类,静态块重跑
- OSGi 模块中,不同 Bundle 使用各自 ClassLoader 加载相同类 → 各自执行一次静态块
- Web 容器(如 Tomcat)为每个应用使用独立 WebAppClassLoader → 两个 WAR 包里的同名类互不影响,各跑一次
- 自定义 ClassLoader 每次 new 一个实例去 loadClass → 每次都是新类,静态块反复执行
静态块执行失败后会发生什么?
一旦静态代码块中抛出未捕获异常(包括 RuntimeException 或 ExceptionInInitializerError),JVM 会将该类标记为“初始化失败”。此后任何对该类的主动使用,都会直接抛出 NoClassDefFoundError,而不是重试初始化。
立即学习“Java免费学习笔记(深入)”;
- 例如:static { throw new RuntimeException("Boom"); } → 后续 new、调用 static 方法全部失败
- 该状态不可恢复,重启应用或重新加载类(换类加载器)是唯一出路
- 常见陷阱:配置文件路径错误、环境变量缺失、静态依赖循环导致 NullPointerException
怎么验证它确实只执行了一次?
最直接的方式是在静态块里加日志或断点,配合典型触发链观察:
- 写一个含 static 块和 static 方法的类,启动时不做任何调用 → 块不执行
- main 中第一次调用 static 方法 → 块执行,日志输出一次
- 紧接着再次调用同一方法、或 new 实例、或读取静态字段 → 日志不再输出
- 用 jstack 或 JFR 查看类初始化事件,可确认仅记录一次 “clinit” 执行


















