应避免在文件操作中途调用System.exit(),必须确保close()等收尾操作先于exit执行;优先使用try-with-resources自动管理资源;业务逻辑中禁用exit,改用正常流程退出;shutdown hook仅作尽力而为的兜底。

System.exit() 会直接终止 JVM,跳过 try-finally、资源释放语句和大部分业务逻辑,因此文件资源极大概率来不及关闭。要确保文件资源关闭,核心不是“让 exit 更可靠”,而是避免在文件操作中途调用 exit——把退出控制权交还给程序自然流程,或在必须强制退出前完成关键收尾。
显式前置关闭文件资源
若确需调用 System.exit()(如启动阶段配置加载失败),必须将 close()、flush() 等操作写在其之前,且顺序不能颠倒:
- 先调用 fileWriter.close() 或 bufferedWriter.flush() & close()
- 再调用 System.exit(1),不能反着来
- 对 FileInputStream/OutputStream 同理,close() 必须执行成功后再 exit
- 注意:即使 close() 抛异常,也应在 catch 中记录日志,再 exit,避免静默失败
优先用 try-with-resources 替代手动管理
这是编译器保障的资源安全机制,不依赖 JVM 退出路径,适用于所有可关闭资源(FileInputStream、FileOutputStream、BufferedReader 等):
- 声明资源时用 try (FileWriter fw = new FileWriter("log.txt")) { ... }
- 无论是否发生异常、是否提前 return 或 throw,编译器都会生成 finally 块自动调用 close()
- 即使后续代码中调用了 System.exit(),该资源也已在作用域结束时关闭
- 多个资源可用逗号分隔,按声明逆序关闭
避免在文件写入中途触发 exit
业务逻辑中(如处理上传文件、生成报表、写日志缓冲区)严禁出现 System.exit()。应改用正常流程退出:
- 主线程用 return 结束 main 方法,让 JVM 自然退出
- 异步写文件任务用 CountDownLatch 或 CompletableFuture 等待完成后再退出
- 服务类应用(如 Spring Boot)统一用 SpringApplication.exit(context),它会触发 Bean 销毁、资源释放等完整生命周期
- 若检测到写入失败,抛出异常并由上层决定是否重试或标记失败,而非直接 exit
用 shutdown hook 做兜底,但不可依赖
仅作为“尽力而为”的补救手段,适合处理未显式管理的文件资源:
- 注册 hook:Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { if (writer != null) writer.close(); } catch (IOException e) { log.error("hook 关闭 writer 失败", e); } }))
- hook 中不要阻塞(如等待网络响应)、不要新建线程、不要调用 System.exit()
- 它只在 exit 后运行,无法挽救已中断的写入;也不能保证执行时机——进程可能被 kill -9 强制终止
- 真正可靠的方案仍是:文件操作期间禁用 exit,靠结构化资源管理和流程控制保安全

















