system.exit() 直接终止 jvm,中止所有线程且不执行 finally;退出前按序运行 shutdown hook、等待其结束、释放资源并返回状态码。

System.exit() 是怎么让整个程序停下来的
它不是退出某个方法,而是直接通知 JVM:“现在就关机”。调用后,JVM 立即中止所有正在运行的线程(包括主线程和非守护线程),不再执行后续任何 Java 字节码。哪怕你把它写在 try-catch 里,对应的 finally 块也不会运行——这点和 return 完全不同。
退出前会做哪些清理工作
虽然终止很果断,但 JVM 并非“拔电源”式关闭。它会按顺序执行以下动作:
- 运行所有已注册的 shutdown hook 线程(按注册顺序反向执行)
- 等待这些 hook 线程全部结束(若某个 hook 阻塞或死循环,程序就会卡住不退出)
- 释放底层资源(如文件句柄、网络连接等),这部分由 JVM 自动完成,无需手动 close
- 向操作系统返回你传入的状态码(如 0 表示成功,1–127 表示各类错误)
关闭钩子(Shutdown Hook)该怎么用
这是实现“优雅退出”的关键机制。它本质是一个 Thread 对象,通过 Runtime.getRuntime().addShutdownHook() 注册,在 JVM 收到退出信号(包括 System.exit、kill -15、Ctrl+C)时自动触发:
- 适合做日志刷盘、数据库连接关闭、临时文件清理、指标上报等收尾操作
- 不能依赖外部服务响应(比如远程 HTTP 调用),因为此时网络栈可能已开始关闭
- 不要在 hook 中调用 System.exit(),否则会造成递归调用和未定义行为
- 多个 hook 之间无执行顺序保证,应避免互相依赖
什么时候该用,什么时候要避开
推荐用:命令行工具参数校验失败、服务启动时发现配置致命错误、安全策略强制中断等“必须立刻停止且无法继续”的场景。
禁止用:Web 应用(如 Spring Boot)、容器化服务、多线程业务逻辑中——这类环境由外部生命周期管理器控制启停,自行调用 System.exit() 可能导致容器误判、集群脑裂或资源残留。
替代思路:抛出异常让上层捕获,或设置标志位由主循环检测退出;真正需要进程级退出时,优先交由运维脚本或容器平台处理。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











