场景描述
在使用Springboot整合定时任务,发现当某个定时任务执行出现执行时间过长的情况时会阻塞其他定时任务的执行。
问题定位
后续通过翻查Springboot的文档以及打印日志(输出当前线程信息)得知问题是由于Springboot默认使用只有1个线程的单线程池处理定时任务。
问题复盘
需要注意示例的Springboot版本为2.1.3.RELEASE。
@Component
@Log4j2public classScheduledTask {
@Scheduled(cron= "0/5 * * * * ?")public void task1() throwsInterruptedException {
log.info("I am task11111111, current thread: {}", Thread.currentThread());while (true) {//模拟耗时任务,阻塞10s
Thread.sleep(10000);break;
}
}
@Scheduled(cron= "0/5 * * * * ?")public voidtask2() {
log.info("I am task22222222, current thread: {}", Thread.currentThread());
}
}
2019-04-24 17:11:15.008 INFO 16868 --- [ scheduling-1] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[scheduling-1,5,main]2019-04-24 17:11:15.009 INFO 16868 --- [ scheduling-1] com.example.demo.task.ScheduledTask : I am task11111111, current thread: Thread[scheduling-1,5,main]2019-04-24 17:11:25.009 INFO 16868 --- [ scheduling-1] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[scheduling-1,5,main]2019-04-24 17:11:30.002 INFO 16868 --- [ scheduling-1] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[scheduling-1,5,main]2019-04-24 17:11:30.003 INFO 16868 --- [ scheduling-1] com.example.demo.task.ScheduledTask : I am task11111111, current thread: Thread[scheduling-1,5,main]2019-04-24 17:11:40.004 INFO 16868 --- [ scheduling-1] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[scheduling-1,5,main]
由结果可见,task1与task2由同一个线程Thread[scheduling-1,5,main]执行,也即该定时任务默认使用单线程,并且由于task1阻塞了10s,导致本应5s执行一次的定时任务10s才执行一次。
解决方法
由于使用的Springboot版本为2.1.3.RELEASE,所以有两种方法解决这个问题
使用Springboot配置
在配置文件中可以配置定时任务可用的线程数:
## 配置可用线程数为10
spring.task.scheduling.pool.size=10
自定义定时任务的线程池
使用自定义的线程池代替默认的线程池
/*** 定时任务配置类
*@authorRJH
* create at 2019-03-29*/@Configurationpublic classScheduleConfig {/*** 此处方法名为Bean的名字,方法名无需固定
* 因为是按TaskScheduler接口自动注入
*@return
*/@BeanpublicTaskScheduler taskScheduler(){//Spring提供的定时任务线程池类
ThreadPoolTaskScheduler taskScheduler=newThreadPoolTaskScheduler();//设定最大可用的线程数目
taskScheduler.setPoolSize(10);returntaskScheduler;
}
}