System.exit() 不触发 finally,但会执行已注册的 ShutdownHook;Runtime.getRuntime().halt() 则两者都不触发。ShutdownHook 在 JVM 正常关闭时运行,但遇 SIGKILL、崩溃、断电等则失效。

不会触发 finally 代码块,但会触发已注册的 ShutdownHook。
这是 Java JVM 的明确行为:System.exit() 是进程级强制终止指令,它跳过所有 Java 层控制流保障机制,包括 finally 块、try-with-resources 的 close() 调用、甚至 return 后续逻辑。只要 System.exit() 在 try 或 catch 中执行,对应的 finally 就完全不会运行——JVM 直接中止字节码执行,控制权瞬间交还操作系统。
但 System.exit() 会启动标准关闭序列,并发执行所有已注册的 shutdown hook(前提是这些 hook 已成功注册且 JVM 尚未崩溃)。这个过程包括:
- 按任意顺序启动所有 shutdown hook 线程
- 等待它们全部完成(无超时机制,若某个 hook 卡死,整个退出将挂住)
- 若启用了
runFinalizersOnExit(已废弃),还会调用未执行的finalize()方法
注意区别:Runtime.getRuntime().halt() 更暴力,它既不触发 shutdown hook,也不执行 finally,等效于 kill -9。
监控 Victron Energy 电力系统,生成包含电池状态、光伏发电量和活动警报的精美每日邮件报告。集成 Vic...
关键提醒:shutdown hook 不是万能保险。以下场景下 hook 也不会执行:
- 接收到
SIGKILL(如kill -9) - JVM 崩溃、OOM 被系统强杀、断电等底层故障
-
halt()被调用
实践建议:
- 关键清理逻辑不要只依赖
finally,应同时注册 shutdown hook 做“尽力而为”的兜底 - 钩子函数必须轻量、幂等、带超时(例如用
CountDownLatch.await(10, TimeUnit.SECONDS)) - 避免在 hook 中再调用
System.exit()或halt(),防止二次中断 - 业务代码中尽量避免
System.exit(),优先用自然退出或框架提供的优雅关闭机制(如 Spring Boot 的SpringApplication.exit())
不复杂但容易忽略。

















