SpringBoot定时任务 @Scheduled 没有准时执行的原因及

问题:

在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注解实现的定时任务??

【文章原创作者:高防cdn gfcdn.html提供,感恩】有多远,走多远,把足迹连成生命线。

SpringBoot定时任务 @Scheduled 没有准时执行的原因及

相关文章:

你感兴趣的文章:

标签云: