springboot——@Scheduled为什么顺序执行
@Scheduled为什么顺序执行
- 1. 场景描述
- 2. 问题原因
- 3. 解决方案
- 4. 配置多线程任务调度器
- 5. 注意事项
- 6. 代码测试demo
- 7. 源码部分
1. 场景描述
场景是这样的两个定时任务分别是每天的4点和5点
@Scheduled(cron = “0 0 4 * * ?”)
@Scheduled(cron = “0 0 5 * * ?”)
4点的任务执行时间很长,一下子到8点
5点的任务为什么是等4点的结束才开始,不是5点直接开始
2. 问题原因
在Spring框架中使用@Scheduled注解定义定时任务时,默认情况下,每个任务都是在
同一个线程中执行的。这意味着,如果一个任务的执行时间很长,它会阻塞后续任务的执行,直到当前任务完成。这就是为什么5点的任务会等待4点的任务结束才开始执行的原因。
3. 解决方案
为了确保定时任务能够按时执行,即使前一个任务还没有完成,您可以配置多个线程来执行定时任务。Spring允许您通过TaskScheduler来配置多个线程池,从而实现并发执行任务。
4. 配置多线程任务调度器
@Configuration
public class SchedulerConfig {@Beanpublic ThreadPoolTaskScheduler taskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setPoolSize(10); // 设置线程池大小scheduler.setThreadNamePrefix("Scheduled-");scheduler.initialize();return scheduler;}
}
5. 注意事项
- 线程安全:确保您的任务方法是线程安全的,因为多个任务可能会同时执行。
- 任务冲突:如果多个任务访问共享资源,需要确保资源的同步或使用适当的并发控制机制。
- 资源管理:合理配置线程池大小,以避免过多的线程消耗系统资源。
- 错误处理:在任务方法中添加适当的错误处理逻辑,以便在任务执行失败时能够恢复或重试。
6. 代码测试demo
@Slf4j
@Component
public class TestSchedule {// 定义一个按照cron表达式定时执行的任务方法task1 每分钟执行1次@Scheduled(cron = "0 * * * * ?")public void task1() {try {// 打印任务开始的信息System.out.println("task1 start");// 模拟任务执行,休眠5秒TimeUnit.SECONDS.sleep(5);// 打印任务结束的信息System.out.println("task1 end");} catch (Exception e) {// 记录任务执行中的错误日志log.error("task1 error:", e);}}// 定义另一个按照相同cron表达式定时执行的任务方法task2 每分钟执行1次@Scheduled(cron = "0 * * * * ?")public void task2() {try {// 打印任务开始的信息System.out.println("task2 start");// 模拟任务执行,休眠5秒TimeUnit.SECONDS.sleep(5);// 打印任务结束的信息System.out.println("task2 end");} catch (Exception e) {// 记录任务执行中的错误日志log.error("task2 error:", e);}}
}
场景1: 不添加配置ThreadPoolTaskScheduler, 执行结果是tast2结束之后开始执行tast1, 顺序执行

场景2: 添加配置ThreadPoolTaskScheduler, 执行结果是tast1和tast1同时开始, 并发执行

7. 源码部分



