System.exit 会强制终止 JVM,跳过所有清理逻辑,应避免在业务中使用;优先采用自然退出(如主线程结束)、优雅关闭(如 Spring Boot 的 exit 方法)或仅在启动失败等极早期场景使用,并辅以 shutdown hook 做尽力而为的收尾。

System.exit 会直接终止 JVM,跳过 try-catch-finally、资源释放语句和大部分业务逻辑,因此未完成的任务(如数据库写入、日志刷盘、文件保存、网络响应)大概率失败。要避免这类问题,核心不是“让 exit 更可靠”,而是“不让 exit 在任务中途被调用”——即把退出控制权交还给程序自然流程,或在必须强制退出前完成关键收尾。
优先用自然退出代替 System.exit
绝大多数场景下,System.exit 并非必需。主线程结束 + 所有非守护线程终止,JVM 就会自动退出(状态码 0)。例如:
- 命令行工具:用 return 退出 main 方法,而非 exit;循环中用标志位控制退出
- 服务类应用(如 Spring Boot):通过 SpringApplication.exit(context, exitCode) 触发优雅关闭,确保 Bean 销毁、连接池关闭、事件发布完成
- 多线程任务:用 CountDownLatch 或 CompletableFuture 等待关键子任务完成后再让主线程结束
必须用 System.exit 时,只用于启动失败等极早期场景
仅限配置加载失败、权限校验不通过、端口被占用等 JVM 尚未进入主业务循环的阶段。此时无活跃任务,无资源需清理。例如:
YZTurboWebAndroid 高性能 Android WebView 容器 SDK 接入。用于在 Android 项目中集成 WebView 容器,实现: (1) WebView 预加载与复用,提升 H5 页面加载速度 (2) 离线包管理,拦截请求优先命中本地资源 (3) JS Bridge 双向通信,Na...
- main 方法开头解析参数失败 → System.exit(2)
- 读取 application.yml 失败且无默认配置 → System.exit(3)
- 连接注册中心超时且重试无效(Dubbo 启动期)→ 放在独立线程中调用 exit,避免阻塞初始化主线程(因某些框架会在同步构造中拦截 exit)
用 shutdown hook 补救关键清理,但不能依赖它保任务完整
shutdown hook 是 exit 后唯一能执行的 Java 层逻辑,适合做“尽力而为”的收尾,但不保证执行成功或及时(如 hook 卡死会导致进程挂起)。适用场景包括:
- 强制刷新日志缓冲区:LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); context.stop();
- 关闭未显式管理的数据库连接(仅作兜底)
- 写入临时状态文件,供下次启动时识别异常中断
注意:hook 中不能再调用 System.exit,也不应启动新线程或等待长耗时操作。
Android 中特别注意 Activity 栈与进程关系
System.exit(0) 在 Android 不等于“退出应用”。若任务栈中仍有未 finish 的 Activity(如从 MainActivity 跳转 NewActivity 后未 finish MainActivity),系统会重建栈并重启进程。正确做法是:
- 退出前遍历并 finish 所有 Activity(可用 ActivityManager 或自维护 Activity 栈)
- 更推荐方案:调用 moveTaskToBack(true) 让应用退到后台,交由系统回收
- 完全退出需求极少,真需要时应结合 finishAffinity() + System.exit(0),且确保无前台 Service

















