文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

关于@Scheduled注解的任务为什么不执行的问题

2024-04-02 19:55

关注

概述

在SpringBoot中可以通过@Scheduled来注解定义一个定时任务,但是有时候你可能发现有的定时任务道理时间却没有执行,但是又不是每次都不执行,为什么呢???

举例说明

下面这段diam定义了一个没隔10s执行一次的定时任务:

package com.study.practice.schedule;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;


@Component
@Slf4j
public class ScheduleTest {
    @Scheduled(cron = "0/10 * * * * ?")
    public void execute() {
        log.info("Scheduled task is running ... ...");
    }
}

记得在启动类或者Configuration类上添加了@EnableScheduling注解。

启动应用,控制台每隔10秒打印一条日志:

2021-12-01 11:27:00.002  INFO 97876 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:27:10.001  INFO 97876 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:27:20.002  INFO 97876 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:27:30.001  INFO 97876 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:27:40.002  INFO 97876 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:27:50.001  INFO 97876 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:28:00.002  INFO 97876 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:28:10.002  INFO 97876 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...

但是,问题才刚刚开始。

在上面的相关代码中,我们使用cron表达式指定的定时任务执行时间点从0秒开始,每隔10s执行一次,现在我们再加一个定时任务:

package com.study.practice.schedule;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;


@Component
@Slf4j
public class ScheduleTestTwo {
    @Scheduled(cron = "0/10 * * * * *")
    public void second() throws InterruptedException {
        log.info("Second scheduled task is running... ...");
        TimeUnit.SECONDS.sleep(5);
    }
}

启动项目,执行结果如下:

2021-12-01 11:36:30.001  INFO 134576 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:36:30.002  INFO 134576 --- [   scheduling-1] c.s.practice.schedule.ScheduleTestTwo    : Second scheduled task is running... ...
2021-12-01 11:36:40.002  INFO 134576 --- [   scheduling-1] c.s.practice.schedule.ScheduleTestTwo    : Second scheduled task is running... ...
2021-12-01 11:36:45.002  INFO 134576 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:36:50.001  INFO 134576 --- [   scheduling-1] c.s.practice.schedule.ScheduleTestTwo    : Second scheduled task is running... ...
2021-12-01 11:36:55.002  INFO 134576 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 11:37:00.001  INFO 134576 --- [   scheduling-1] c.s.practice.schedule.ScheduleTestTwo    : Second scheduled task is running... ...
2021-12-01 11:37:05.001  INFO 134576 --- [   scheduling-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...

可以看到任务1和任务2本该都是每个10s执行,但是却发现只有任务2执行了,任务1却等待了5s之后才执行。

原因分析

为了找到原因,我们从@Scheduled注解的源码开始分析:

下面是@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:

    
    public void setScheduler(Object scheduler) {
        this.scheduler = scheduler;
    }

重点来了,注意这句话:

if neither of two is resolvable, a local single-thread default scheduler will be created within in the registrar.

这句话意味着,如果我们不主动配置我们需要的TaskScheduler,SpringBoot会默认使用一个单线程的scheduler来处理我们用@Scheduled注解实现的定时任务,到此我们刚才的问题就可以理解了。

因为是单个线程执行所有的定时任务,所有task2如果先执行,因为执行中等待了5s,所以task2执行完后,task1接着继续执行。

解决方案

搞清楚这个流程后,解决这个问题就很简单了。

根据刚才注释的描述,我们只需要提供一个满足自己需要的TaskScheduler并注册到context容器中就可以了。

package com.study.practice.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;


@Configuration
public class ScheduledTaskConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(2);
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);
    }
}

上面的代码提供了一个线程池大小为2的taskScheduler,再次启动SpringBoot查看效果。

2021-12-01 14:05:20.001  INFO 39768 --- [TaskScheduler-2] c.s.practice.schedule.ScheduleTestTwo    : Second scheduled task is running... ...
2021-12-01 14:05:20.001  INFO 39768 --- [TaskScheduler-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 14:05:30.002  INFO 39768 --- [TaskScheduler-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 14:05:30.002  INFO 39768 --- [TaskScheduler-2] c.s.practice.schedule.ScheduleTestTwo    : Second scheduled task is running... ...
2021-12-01 14:05:40.001  INFO 39768 --- [TaskScheduler-1] c.study.practice.schedule.ScheduleTest   : Scheduled task is running ... ...
2021-12-01 14:05:40.001  INFO 39768 --- [TaskScheduler-2] c.s.practice.schedule.ScheduleTestTwo    : Second scheduled task is running... ...

可以看到,当线程池里有两个线程时,这两个任务各种按照预定的时间进行触发,互不影响了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯