SpringBoot中@Scheduled定时任务未按时执行,原因和解决方法有哪些?
- 内容介绍
- 文章标签
- 相关推荐
本文共计2358个文字,预计阅读时间需要10分钟。
问题:在Spring Boot项目中设置了5个定时任务,突然有一天部分定时任务不再执行,重启程序定时任务也不执行,这是什么原因?
经过查阅资料,以下是关于定时任务异常的一些可能原因:
1. Spring Boot版本问题:不同版本的Spring Boot对定时任务的支持可能存在差异,建议检查项目使用的Spring Boot版本是否与定时任务实现兼容。
2. 配置错误:检查定时任务的配置是否正确,包括cron表达式、任务执行类等。
3. 线程池问题:如果使用了线程池,可能存在线程池被耗尽或任务执行时间过长导致线程池阻塞的情况。
4. 任务依赖:如果任务之间存在依赖关系,可能因为某个任务执行失败导致后续任务无法执行。
5. 任务执行异常:任务执行过程中出现异常,导致任务无法继续执行。
6. 系统资源限制:系统资源(如内存、CPU)不足,导致定时任务无法正常执行。
7. Spring Boot启动类问题:如果启动类存在异常,可能导致定时任务无法启动。
8. 定时任务类问题:定时任务类存在异常,导致任务无法执行。
建议按照以下步骤排查问题:
1. 检查配置:仔细检查定时任务的配置,确保cron表达式、任务执行类等无误。
2. 查看日志:查看Spring Boot启动日志和定时任务执行日志,查找异常信息。
3. 检查线程池:如果使用了线程池,检查线程池配置和任务执行情况。
4. 检查任务依赖:确保任务依赖关系正确,没有任务因执行失败而影响其他任务。
5. 检查系统资源:检查系统资源是否充足,确保定时任务可以正常执行。
6. 检查启动类和任务类:检查启动类和任务类是否存在异常。
通过以上步骤,相信可以找到定时任务异常的原因。
问题:
在spring boot 项目中设置了共13个定时任务,突然有一天部分定时任务就不再执行了,重启程序定时任务也不执行,莫名其妙,查了好多资料,以下是关于我查到的关于定时任务突然停掉的一些原因。
排查:
查到了大部分经验说是spring boot中得定时任务都时单线程得,要进行多线程执行;
单线程测试:
package com.example.demo.conf;import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.concurrent.TimeUnit;import static java.lang.Thread.sleep;@Component//@EnableAsync //开启多线程public class SaticScheduleTask { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron1() { System.out.println("第1个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron2() { System.out.println("第2个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron3() { System.out.println("第3个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron4() { System.out.println("第4个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron5() { System.out.println("第5个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 1 * * ?") public void jobCron6() { System.out.println("第6个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron7() { System.out.println("第7个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 0 1 11 ?") public void jobCron8() { System.out.println("第8个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 2 * * ?") public void jobCron9() { System.out.println("第9个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron10() throws InterruptedException { System.out.println("第10个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(600); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT1M") public void jobCron11() throws InterruptedException { System.out.println("第11个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT20S") public void jobCron12() throws InterruptedException { System.out.println("第12个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(360); } @Async @Scheduled(cron = "0 45 10 * * ?") public void jobCron13() { System.out.println("第13个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); }}测试结果:当有多个定时任务时,其中一个耗时比较长会影响其他定时任务执行,执行结果可以看出设定的第13个定时任务为每天10:45执行,到时间并未执行
解决方法:
方法一:改为多线程:
package com.example.demo.conf;import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.concurrent.TimeUnit;import static java.lang.Thread.sleep;@Component@EnableAsync //开启多线程public class SaticScheduleTask { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron1() { System.out.println("第1个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron2() { System.out.println("第2个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron3() { System.out.println("第3个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron4() { System.out.println("第4个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron5() { System.out.println("第5个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 1 * * ?") public void jobCron6() { System.out.println("第6个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron7() { System.out.println("第7个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 0 1 11 ?") public void jobCron8() { System.out.println("第8个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 2 * * ?") public void jobCron9() { System.out.println("第9个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron10() throws InterruptedException { System.out.println("第10个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT1M") public void jobCron11() throws InterruptedException { System.out.println("第11个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT20S") public void jobCron12() throws InterruptedException { System.out.println("第12个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(360); } @Async @Scheduled(cron = "0 55 10 * * ?") public void jobCron13() { System.out.println("第13个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); }}结果:按指定时间执行了,并没有受到其他比较耗时的任务影响
方法二(推荐):改为线程池
下面的代码提供了一个线程池大小为13的taskScheduler
package com.example.demo.conf;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.SchedulingConfigurer;import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;import org.springframework.scheduling.config.ScheduledTaskRegistrar;@Configurationpublic class ScheduledTaskConfiguration implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { final ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(13); taskScheduler.initialize(); taskRegistrar.setTaskScheduler(taskScheduler); }}package com.example.demo.conf;import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.concurrent.TimeUnit;import static java.lang.Thread.sleep;@Component//@EnableAsync //开启多线程public class SaticScheduleTask { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron1() { System.out.println("第1个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron2() { System.out.println("第2个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron3() { System.out.println("第3个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron4() { System.out.println("第4个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron5() { System.out.println("第5个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 1 * * ?") public void jobCron6() { System.out.println("第6个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron7() { System.out.println("第7个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 0 1 11 ?") public void jobCron8() { System.out.println("第8个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 2 * * ?") public void jobCron9() { System.out.println("第9个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron10() throws InterruptedException { System.out.println("第10个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT1M") public void jobCron11() throws InterruptedException { System.out.println("第11个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT20S") public void jobCron12() throws InterruptedException { System.out.println("第12个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(360); } @Async @Scheduled(cron = "0 05 11 * * ?") public void jobCron13() { System.out.println("第13个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); }}结果:按指定时间执行了,并没有受到其他比较耗时的任务影响
附:分析@Scheduled注解的源码
/** * <p>Processing of {@code @Scheduled} annotations is performed by * registering a {@link ScheduledAnnotationBeanPostProcessor}. This can be * done manually or, more conveniently, through the {@code <task:annotation-driven/>} * element or @{@link EnableScheduling} annotation. */每一个有@Scheduled注解的方法都会被注册为一个ScheduledAnnotationBeanPostProcessor, 再接着往下看ScheduledAnnotationBeanPostProcessor:
/** * Set the {@link org.springframework.scheduling.TaskScheduler} that will invoke * the scheduled methods, or a {@link java.util.concurrent.ScheduledExecutorService} * to be wrapped as a TaskScheduler. * <p>If not specified, default scheduler resolution will apply: searching for a * unique {@link TaskScheduler} bean in the context, or for a {@link TaskScheduler} * bean named "taskScheduler" otherwise; the same lookup will also be performed for * a {@link ScheduledExecutorService} bean. If neither of the two is resolvable, * a local single-threaded default scheduler will be created within the registrar. * @see #DEFAULT_TASK_SCHEDULER_BEAN_NAME */public void setScheduler(Object scheduler) { this.scheduler = scheduler;}重点来了, 注意这句话:
If neither of the two is resolvable,a local single-threaded default scheduler will be created within the registrar.这句话意味着, 如果我们不主动配置我们需要的TaskScheduler,SpringBoot 会默认使用一个单线程的scheduler来处理我们用@Scheduled注解实现的定时任务
本文共计2358个文字,预计阅读时间需要10分钟。
问题:在Spring Boot项目中设置了5个定时任务,突然有一天部分定时任务不再执行,重启程序定时任务也不执行,这是什么原因?
经过查阅资料,以下是关于定时任务异常的一些可能原因:
1. Spring Boot版本问题:不同版本的Spring Boot对定时任务的支持可能存在差异,建议检查项目使用的Spring Boot版本是否与定时任务实现兼容。
2. 配置错误:检查定时任务的配置是否正确,包括cron表达式、任务执行类等。
3. 线程池问题:如果使用了线程池,可能存在线程池被耗尽或任务执行时间过长导致线程池阻塞的情况。
4. 任务依赖:如果任务之间存在依赖关系,可能因为某个任务执行失败导致后续任务无法执行。
5. 任务执行异常:任务执行过程中出现异常,导致任务无法继续执行。
6. 系统资源限制:系统资源(如内存、CPU)不足,导致定时任务无法正常执行。
7. Spring Boot启动类问题:如果启动类存在异常,可能导致定时任务无法启动。
8. 定时任务类问题:定时任务类存在异常,导致任务无法执行。
建议按照以下步骤排查问题:
1. 检查配置:仔细检查定时任务的配置,确保cron表达式、任务执行类等无误。
2. 查看日志:查看Spring Boot启动日志和定时任务执行日志,查找异常信息。
3. 检查线程池:如果使用了线程池,检查线程池配置和任务执行情况。
4. 检查任务依赖:确保任务依赖关系正确,没有任务因执行失败而影响其他任务。
5. 检查系统资源:检查系统资源是否充足,确保定时任务可以正常执行。
6. 检查启动类和任务类:检查启动类和任务类是否存在异常。
通过以上步骤,相信可以找到定时任务异常的原因。
问题:
在spring boot 项目中设置了共13个定时任务,突然有一天部分定时任务就不再执行了,重启程序定时任务也不执行,莫名其妙,查了好多资料,以下是关于我查到的关于定时任务突然停掉的一些原因。
排查:
查到了大部分经验说是spring boot中得定时任务都时单线程得,要进行多线程执行;
单线程测试:
package com.example.demo.conf;import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.concurrent.TimeUnit;import static java.lang.Thread.sleep;@Component//@EnableAsync //开启多线程public class SaticScheduleTask { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron1() { System.out.println("第1个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron2() { System.out.println("第2个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron3() { System.out.println("第3个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron4() { System.out.println("第4个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron5() { System.out.println("第5个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 1 * * ?") public void jobCron6() { System.out.println("第6个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron7() { System.out.println("第7个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 0 1 11 ?") public void jobCron8() { System.out.println("第8个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 2 * * ?") public void jobCron9() { System.out.println("第9个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron10() throws InterruptedException { System.out.println("第10个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(600); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT1M") public void jobCron11() throws InterruptedException { System.out.println("第11个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT20S") public void jobCron12() throws InterruptedException { System.out.println("第12个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(360); } @Async @Scheduled(cron = "0 45 10 * * ?") public void jobCron13() { System.out.println("第13个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); }}测试结果:当有多个定时任务时,其中一个耗时比较长会影响其他定时任务执行,执行结果可以看出设定的第13个定时任务为每天10:45执行,到时间并未执行
解决方法:
方法一:改为多线程:
package com.example.demo.conf;import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.concurrent.TimeUnit;import static java.lang.Thread.sleep;@Component@EnableAsync //开启多线程public class SaticScheduleTask { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron1() { System.out.println("第1个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron2() { System.out.println("第2个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron3() { System.out.println("第3个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron4() { System.out.println("第4个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron5() { System.out.println("第5个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 1 * * ?") public void jobCron6() { System.out.println("第6个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron7() { System.out.println("第7个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 0 1 11 ?") public void jobCron8() { System.out.println("第8个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 2 * * ?") public void jobCron9() { System.out.println("第9个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron10() throws InterruptedException { System.out.println("第10个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT1M") public void jobCron11() throws InterruptedException { System.out.println("第11个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT20S") public void jobCron12() throws InterruptedException { System.out.println("第12个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(360); } @Async @Scheduled(cron = "0 55 10 * * ?") public void jobCron13() { System.out.println("第13个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); }}结果:按指定时间执行了,并没有受到其他比较耗时的任务影响
方法二(推荐):改为线程池
下面的代码提供了一个线程池大小为13的taskScheduler
package com.example.demo.conf;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.SchedulingConfigurer;import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;import org.springframework.scheduling.config.ScheduledTaskRegistrar;@Configurationpublic class ScheduledTaskConfiguration implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { final ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(13); taskScheduler.initialize(); taskRegistrar.setTaskScheduler(taskScheduler); }}package com.example.demo.conf;import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.concurrent.TimeUnit;import static java.lang.Thread.sleep;@Component//@EnableAsync //开启多线程public class SaticScheduleTask { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron1() { System.out.println("第1个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron2() { System.out.println("第2个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron3() { System.out.println("第3个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron4() { System.out.println("第4个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 */10 * * * ?") public void jobCron5() { System.out.println("第5个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 1 * * ?") public void jobCron6() { System.out.println("第6个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron7() { System.out.println("第7个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 0 1 11 ?") public void jobCron8() { System.out.println("第8个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(cron = "0 0 2 * * ?") public void jobCron9() { System.out.println("第9个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT30S") public void jobCron10() throws InterruptedException { System.out.println("第10个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT1M") public void jobCron11() throws InterruptedException { System.out.println("第11个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(120); } @Async @Scheduled(initialDelayString = "PT1M", fixedDelayString = "PT20S") public void jobCron12() throws InterruptedException { System.out.println("第12个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(360); } @Async @Scheduled(cron = "0 05 11 * * ?") public void jobCron13() { System.out.println("第13个定时任务开始 : " + LocalDateTime.now().format(FORMATTER) + " 线程 : " + Thread.currentThread().getName()); }}结果:按指定时间执行了,并没有受到其他比较耗时的任务影响
附:分析@Scheduled注解的源码
/** * <p>Processing of {@code @Scheduled} annotations is performed by * registering a {@link ScheduledAnnotationBeanPostProcessor}. This can be * done manually or, more conveniently, through the {@code <task:annotation-driven/>} * element or @{@link EnableScheduling} annotation. */每一个有@Scheduled注解的方法都会被注册为一个ScheduledAnnotationBeanPostProcessor, 再接着往下看ScheduledAnnotationBeanPostProcessor:
/** * Set the {@link org.springframework.scheduling.TaskScheduler} that will invoke * the scheduled methods, or a {@link java.util.concurrent.ScheduledExecutorService} * to be wrapped as a TaskScheduler. * <p>If not specified, default scheduler resolution will apply: searching for a * unique {@link TaskScheduler} bean in the context, or for a {@link TaskScheduler} * bean named "taskScheduler" otherwise; the same lookup will also be performed for * a {@link ScheduledExecutorService} bean. If neither of the two is resolvable, * a local single-threaded default scheduler will be created within the registrar. * @see #DEFAULT_TASK_SCHEDULER_BEAN_NAME */public void setScheduler(Object scheduler) { this.scheduler = scheduler;}重点来了, 注意这句话:
If neither of the two is resolvable,a local single-threaded default scheduler will be created within the registrar.这句话意味着, 如果我们不主动配置我们需要的TaskScheduler,SpringBoot 会默认使用一个单线程的scheduler来处理我们用@Scheduled注解实现的定时任务

