• Springboot使用定时任务scheduler详解


    认识

    能够让我们在指定的某个时间段自动执行任务,不需要自己去手动触发。
    如:定时发送邮件、定时发送优惠卷等…

    示例代码

    文章中的代码,保存在Gitee

    定时任务 / 调度任务

    开启调度

    • 默认情况下不开启定时任务,如果想使用添加@EnableScheduling来显示启动

      @SpringBootApplication
      @EnableScheduling
      public class SpringSchedulerApplication {
          public static void main(String[] args) {
              SpringApplication.run(SpringSchedulerApplication.class, args);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 更好的做法,是定义一个定时器的配置类,在结合@ConditionalOnProperty控制定时任务的开启和关闭

      @Configuration
      @EnableScheduling
      // 默认为false, 配置为true代表开启定时功能, 
      @ConditionalOnProperty(name = "scheduler.enabled", matchIfMissing = true) 
      public class SchedulerConfig {
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    添加定时任务

    默认单位都为毫秒(ms)

    以固定延迟执行定时任务–fixedDelay

    • fixedDelay属性配置定时任务在指定延迟时间后执行

    • 新任务要等待前一个任务完成,示例如下:

      @Scheduled(fixedDelay = 2000)
      public void computePrice() throws InterruptedException {
        log.info("current time: {}", LocalTime.now());
        Thread.sleep(4000);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 每2秒执行一次

      • 在新任务开启前, 需要等待旧任务完成。因此我们可以看到6秒后才会执行下一个任务

    以固定速率执行定时任务–fixedRate

    • fixedRate属性配置定时任务以固定时间执行定时任务,示例如下:

      @Scheduled(fixedRate = 3000)
      public void refreshPricingParameters() throws InterruptedException {
        log.info("current time: {}", LocalTime.now());
        Thread.sleep(6000);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 在这里,我们通过设置fixedRate为3000毫秒,使refreshPricingParameters方法每隔3秒就会执行一次。

      • 但是由于Scheduled默认是单线程,导致打印时间为6秒间隔(Thread.sleep(6000))

      • 如果想不被前一个任务的影响,可以通过下面两种方法解决:

        1. 通过开启异步任务

          @Configuration
          @EnableScheduling
          @EnableAsync // 开启异步任务
          @ConditionalOnProperty(name = "scheduler.enabled", matchIfMissing = true) 
          public class SchedulerConfig {
          }
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          @Scheduled(fixedRate = 3000)
          @Async // 异步执行
          public void refreshPricingParameters() throws InterruptedException {
            log.info("current time: {}", LocalTime.now());
            Thread.sleep(6000);
          }
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
        2. 定时器默认不并行执行是因为线程池默认大小为1,可以通过配置**spring.task.scheduling.pool.size**调整线程池大小。

    延迟第一次初始化–initialDelay

    • 使用fixedRatefixedDelay属性,方法的第一次调用,会在上下文初始化完成后通过指定的时间进行调度。

    • 但是可以通过initialDelay 属性,指定第一次方法执行的延迟时间。示例如下:

      // 第一次延迟5秒后执行, 后续延迟都为3秒
      @Scheduled(initialDelay = 5000, fixedRate = 3000)
      @Async
      public void refreshPricingParametersTemp() {
        log.info("current time: {}", LocalTime.now());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 在这里,将方法第一次执行延迟时间设置为5秒

    以 ISO 时间格式指定间隔–fixedRateString

    • 可以通过这个文档ISO-文档了解ISO时间格式,示例如下:

      @Scheduled(fixedDelayString = "PT02S")
      public void computePrice_TEMP() throws InterruptedException {
        log.info("current time: {}", LocalTime.now());
        Thread.sleep(4000);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 在这里,设置fixedDelayString值为PT02S,表示调用之间以 2 秒的固定延迟执行。
    • 除此之外,fixedDelayString还支持读取配置文件进行设置,示例如下:

      @Scheduled(fixedDelayString = "${interval}")
      public void computePriceTemp() throws InterruptedException {
        log.info("current time: {}", LocalTime.now());
        Thread.sleep(4000);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      // yaml设置
      interval: PT02S
      // properties设置
      interval=PT02S
      
      • 1
      • 2
      • 3
      • 4

    使用 Cron 表达式定义间隔

    • cron表达式,用于设置更加复杂的时间。示例如下:

      @Scheduled(cron = "0/2 * * * * ?")
      public String computePrice() throws InterruptedException {
        log.info("current time: {}", LocalTime.now());
        return "";
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 在这里,指定cron0/2 * * * * ?,表示每间隔2秒进行执行
      • 注:cron支持读取配置文件
    • cron表达式格式,我们可以参考Spring官方的调度示例进行学习

      ┌────────────── 秒 (0-59)
       │ ┌───────────── 分钟 (0 - 59)
       │ │ ┌───────────── 小时 (0 - 23)
       │ │ │ ┌───────────── 一个月中的某天 (1 - 31)
       │ │ │ │ ┌───────────── 月(1-12)(或JAN-DEC)
       │ │ │ │ │ ┌───────────── 星期几(0 - 7)
       │ │ │ │ │ │ (0 或 7 为星期日,或 MON-SUN)
       │ │ │ │ │ │
       * * * * * *
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

    结论

    • Scheduler调度是核心模块,不需要添加其他依赖
    • 默认情况下不开启调度,需要使用@EnableScheduling显示开启
    • 结合@ConditionalOnProperty设置是否开启或禁用调度任务
    • @Scheduled注解的方法,表示开启定时任务
    • fixedRatefixedDelay设置执行间隔
    • initialDelay设置第一次方法执行的延迟时间

    上述的代码示例都已上传到Gitee
    参考文章:

  • 相关阅读:
    MybatisPlus rewriteBatchedStatements=true 批量插入失效,依然是单条插入问题解决
    【Java从入门到精通 03】:Java运算符及进制转换
    华为OD机试 - 羊、狼、农夫过河 - 逻辑分析(Java 2022 Q4 100分)
    C++ 之LeetCode刷题记录(三十六)
    23种设计模式3
    网络安全(黑客)—-2024自学手册
    python练习(5)
    vue 修改 el-cascader 面板的样式
    一文掌握Vue3:深度解读Vue3新特性、Vue2与Vue3核心差异以及Vue2到Vue3转型迭代迁移重点梳理与实战
    【ARM Coresight 系列文章19 -- Performance Monitoring Unit(性能监测单元)
  • 原文地址:https://blog.csdn.net/qq_42191033/article/details/126466491