结合 Spring Boot 定时任务(@Scheduled + Quartz)的生产实战经验,下面把最容易踩坑、必须遵守的注意事项整理成核心清单,覆盖基础规范、执行机制、集群、异常、稳定性等,全是实战干货:
一、基础使用规范(错了直接不生效)
-
任务方法硬性要求
定时任务方法必须是:public + 无参数 + void 无返回值,不能是 private/static 方法;任务类必须添加 @Component 交给 Spring 管理,否则注解不生效。
-
必须开启总开关
启动类必须加 @EnableScheduling,忘记加 → 所有定时任务直接不执行。
-
避免循环依赖/内部调用
不能在类内部直接调用 @Scheduled 方法(比如 this.executeTask()),Spring AOP 无法拦截,注解失效。
二、执行机制(90%的故障都源于此)
-
默认单线程,会全局阻塞!
@Scheduled 底层默认单线程池:
✖ 一个任务卡死/耗时过长 → 所有定时任务全部阻塞、不执行。
✅ 解决方案:必须自定义多线程池。
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(3);
taskScheduler.setThreadNamePrefix("my-task-"); // 线程名称(排查问题必备)
taskScheduler.setWaitForTasksToCompleteOnShutdown(true); // 优雅停机
taskScheduler.setAwaitTerminationSeconds(60);
return taskScheduler;
}
-
fixedRate / fixedDelay 绝对不能混用
fixedRate:从上一次开始时间计算间隔,任务超时会并发堆积;
fixedDelay:从上一次结束时间计算间隔,绝对串行,无并发。业务中优先用 fixedDelay,更安全。
-
Cron 表达式致命禁忌
- 6 位格式:
秒 分 时 日 月 周,日 和 周 必须一个为 ?,不能同时指定(语法错误);
- 不要写无效值(秒:0-59,分:0-59,时:0-23);
- 低版本 Spring 不支持年(第7位),尽量用 6 位表达式。
-
任务耗时 > 执行周期 = 灾难
单线程下:任务执行 10s,却设置每秒执行 → 任务会不断错过执行、堆积,最终导致服务异常。
三、集群/分布式环境(生产环境必处理)
-
@Scheduled集群会重复执行!
集群部署多个节点时,所有机器都会同时执行同一个定时任务,导致:重复扣款、重复推送、重复统计、数据错乱。
✅ 解决方案:
- 加分布式锁(Redis Redlock、Redisson);
- 改用 Quartz(天然支持集群,仅一个节点执行)。
-
任务必须保证幂等性
无论任务执行多少次,结果必须一致(比如用唯一ID、状态位判断,避免重复操作)。
四、异常处理(任务中断的元凶)
-
必须手动捕获异常
定时任务如果抛出未捕获异常,会直接导致该任务永久停止执行(其他任务不受影响)!
✅ 规范写法:
@Scheduled(cron = "0/1 * * * * ?")
public void task() {
try {
// 业务逻辑
} catch (Exception e) {
// 打印日志 + 告警,绝对不能抛出异常
log.error("定时任务执行失败", e);
}
}
-
禁止无限阻塞
调用第三方接口、数据库操作必须加超时时间,避免线程永久卡死,占用线程池资源。
五、稳定性与持久化
-
内存任务重启即丢失
@Scheduled、Quartz 默认都把任务存在内存中:项目重启/部署 → 正在执行的任务丢失,执行记录清空。
✅ 解决方案:Quartz 配置 JDBC 持久化到数据库。
-
禁止在定时任务中启动新线程
手动创建线程会脱离 Spring 管理,导致无法控制、内存泄漏。
六、生产运维必备
-
必须打印完整日志
记录:任务名称、开始时间、结束时间、执行耗时、异常信息,方便排查问题。
-
动态任务注意线程安全
动态修改 Cron 表达式时,必须加锁,避免并发修改导致调度异常。
-
避免大任务占用资源
定时任务不要做大数据量操作(如全表查询),会拖垮整个服务。
极简总结(记住这 5 条就够了)
- 一定配多线程池,杜绝单线程阻塞;
- 一定try-catch,防止异常终止任务;
- 集群一定加分布式锁,避免重复执行;
- Cron 一定日周互斥,语法不写错;
- 任务一定幂等,耗时一定小于执行周期。
|