定时任务必须在最外层用try-catch捕获exception(含受检异常),记录完整堆栈,finally释放资源,分层处理异常类型,并配合监控告警与兜底机制防止静默失效。

定时任务一旦抛出未捕获异常,线程会终止,后续调度直接停止——不是重试,而是彻底消失。所以捕获异常不是“可选优化”,而是防止任务静默失效的刚性要求。
必须在任务方法最外层加 try-catch
Spring @Scheduled、Quartz Job 或 ScheduledExecutorService 提交的 Runnable/Callable,都必须在执行体最开始就用 try-catch 包住全部业务逻辑。
- 别指望 @ControllerAdvice 或全局异常处理器:它们只对 Web 层生效,对定时任务无效
- 必须 catch Exception(不只是 RuntimeException):IOException、SQLException、JSONException 等受检和非受检异常都要覆盖
- 日志必须打完整堆栈:logger.error("订单扫描失败", e),不能只写 e.getMessage()
finally 块强制释放资源
数据库连接、文件流、Redis 连接、ReentrantLock 等,只要开了就得关——而且必须在 finally 里关。
- try-with-resources 可自动管理 AutoCloseable 资源,优先使用
- 手动 close() 或 unlock() 写在 try 或 catch 里都不安全:一旦前面抛异常或 return,后续代码不执行
- finally 是 JVM 正常运行时的“最后防线”,哪怕 catch 里又抛新异常,它也照常执行
分层捕获,按语义做差异化处理
统一 catch(Exception e) 看似省事,实则掩盖根因。应根据异常类型决定是重试、告警还是人工介入。
- IOException / SQLException:可能是临时抖动,记录 warn 日志 + 短延时重试(需幂等)
- NullPointerException / IllegalArgumentException:暴露代码缺陷,记录 error + 完整堆栈 + 触发告警
- 自定义业务异常(如 OrderStatusException):明确语义,便于监控分类和补偿流程
搭配监控与第二道防线
单靠 try-catch 不够,线上必须建立可观测闭环。
- 用 Micrometer 暴露执行成功/失败次数、耗时、最近执行时间等指标
- 配置 Prometheus 告警规则:例如“5 分钟内失败 ≥3 次”立即通知
- 为 ScheduledExecutorService 设置 errorHandler(Spring 场景)或 UncaughtExceptionHandler(裸线程池场景),作为漏网异常的兜底
- 关键任务加 Redis 心跳 key:每次成功执行后更新过期时间,监控端定期检查并告警过期
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











