背景
@Component
@EnableScheduling
@EnableAsync
public class DemoTask {
private static Logger logger = LoggerFactory.getLogger(DemoTask.class);
@Scheduled(cron = "0 42 18 20 10 ?")
@Async
public void task1(){
logger.warn("exec task1 start...")
// 仅执行一次的任务,需要花费半个小时
}
@Scheduled(cron = "0 0/1 * * * ?")
@Async
public void task2(){
logger.warn("exec task2 start...")
// 每分钟执行一次的任务
}
}
因为某次需求,需要修复一批历史数据,大概要给80多万条老记录打上标签,于是乎就写了执行一次的定时任务task1,任务跑的时间有些久,执行过程中惊讶发现其他短时间执行的任务task2在我这个定时任务运行的过程中全部暂停了,就觉得有些不对劲,开始了下边探索。
个中原由
由于Spring中添加了@Scheduled注解的定时任务默认都在一个线程中执行,也就是说定时任务task1在执行过程中定时任务task2会一直在等待定时任务task1执行完成。这就导致了当某个定时任务需要长时间执行时其他短时间的定时任务全部暂停的现象。
加了@Async注解只是把任务异步提交了,但执行的线程还是一个。
把执行定时任务的线程改为多线程那这样的问题就可以得到解决啦:)
解决办法
1、继承 SchedulingConfigurer 类,重写 configureTasks 方法
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(20));
}
}
2、自已定义 TaskScheduler bean[推荐]
@Configuration
@EnableAsync
public class ScheduleConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(20);
return taskScheduler;
}
}
在每个定时任务方法上除了加@Scheduled外,还需要添加@Async注解
这两种方法的区别欢迎楼下评论探讨啊:)