spring定时任务@EnableScheduling
默认单线程执行造成了的后果:
假设有两个任务A,B,任务预期开始执行的时间分别是t(a),t(b),它们执行需要花费的时间分别为run_time(a),run_time(b)
- 如果t(a)=t(b),那么单线程环境下只能有一个任务开始先执行,另一个任务必须等待前一个任务执行结束才会开始,假设A任务首先开始,那么B任务实际开始执行的时间是t(a)+run_time(a)
- 如果t(a)<t(b),且run_time(a)>t(b)-t(a),那么单线程情况下b任务实际开始执行的时间时为t(a)+run_time(a)所以实际开发过程中如果有一个任务执行时间超长,其它的任务就都会一直被延迟.
我们来查找一下源代码,确认一下为何定时任务默认是单线程执行的:
-
@EnableScheduling注解的源码上有一行
@Import(SchedulingConfiguration.class)
,导入了SchedulingConfiguration.class,在这个配置类中定义了ScheduledAnnotationBeanPostProcessor这个bean是专门用来处理@Scheduled注解的一个后置处理器,在这个类中实现了org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
这个方法,这个方法中扫描了对应类中的@Scheduled注解,然后开始调用org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#processScheduled
这个方法来处理该注解,这个方法的主要目的将定时任务注册到ScheduledTaskRegistrar中,定时任务又分为三类fixDelay,fixRate,corn,之后这个bean后置处理器的工作就完成了. -
之后开始执行
org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#afterSingletonsInstantiated
这是一个生命周期方法,这个生命周期方法又调用了org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#finishRegistration
,又调用了org.springframework.scheduling.config.ScheduledTaskRegistrar#afterPropertiesSet
,又调用了org.springframework.scheduling.config.ScheduledTaskRegistrar#scheduleTasks
这里才是重头戏,前面都是在注册定时任务,这里将要启动定时任务,通过Executors.newSingleThreadScheduledExecutor();
启动了一个单线程的taskScheduler,代码段摘录如下:
1 |
|
所以我们可以通过定义一个配置类来启用多线程,如下:
1 |
|