system.exit() 是强行终止 jvm 的危险操作,应避免使用;可靠退出需依赖自然结束、spring boot 的 exit()、多线程等待及 shutdown hook 等机制,并响应 sigterm 信号实现优雅关闭。

System.exit() 不是退出程序的“按钮”,而是强行拔掉电源——它跳过所有清理逻辑,直接终止 JVM。真正可靠的关闭策略,是把退出变成一个可控制、可等待、可收尾的过程。
优先让程序自然结束
多数场景根本不需要 System.exit()。JVM 会在主线程结束、且没有非守护线程存活时自动退出,状态码默认为 0。
- 命令行工具:main 方法执行完 return 即可,无需 exit(0)
- 循环任务:用布尔标志位控制 while 循环退出,再让主线程自然结束
- Spring Boot 应用:调用 SpringApplication.exit(context, code),触发 Bean 销毁、连接池关闭等完整生命周期
- 多线程任务:用 CountDownLatch 或 CompletableFuture.await() 等待关键子任务完成后再退出主线程
必须强制退出时,只用于极早期失败
仅限 JVM 尚未进入业务主流程的阶段,此时无活跃资源、无待处理任务,退出不会造成数据丢失或状态残留。
- 配置加载失败(如 application.yml 解析异常)
- 端口被占用、权限不足等启动校验不通过
- 注册中心连接超时且重试无效(需在独立线程中调用,避免阻塞初始化主线程)
用 shutdown hook 做尽力而为的收尾
System.exit() 本身不清理资源,但会触发已注册的 shutdown hook。这是 JVM 层级唯一能“插队”执行的清理机制。
- 注册方式:Runtime.getRuntime().addShutdownHook(new Thread(() -> { closeDB(); flushLogs(); }));
- 钩子必须轻量、幂等、带超时(如 await(10, SECONDS)),不能阻塞或依赖外部服务
- 避免在钩子里调用 System.exit() 或 Runtime.halt(),否则可能中断整个清理链
- 注意:kill -9、JVM 崩溃、halt() 调用等场景下,hook 不会执行——它只是优雅退出的“尽力而为”保障
信号驱动的优雅关闭更符合生产规范
在容器、K8s 或 systemd 环境中,进程应响应 SIGTERM 信号,而非主动调用 exit()。这是标准运维实践。
- Java 应用可监听 SIGTERM(通过 Signal.handle 或第三方库),触发自定义关闭流程
- Python 项目常用 signal.signal(signal.SIGTERM, handler) + atexit.register() 组合
- Web 服务需同步停止监听器、取消异步任务、持久化内存状态、关闭数据库连接
- Android 应用严禁 System.exit(0),应通过 finishAffinity() 关闭 Activity 栈,并显式 stopService() 或 unbind











