• Spring Boot 2.x系列【18】功能篇之多线程定时任务


    有道无术,术尚可求,有术无道,止于术。

    本系列Spring Boot版本2.7.0

    前言

    在实际开发中,定时任务功能是我们经常需要的,除了JDK 自带,也有很多实现定时任务的框架,比如 SpringXXL-JOBQuartzElastic Job 等等。

    接下来我们学习下在Spring Boot 中,如何使用Spring Scheduler创建定时任务。

    单线程任务

    使用@EnableScheduling @Scheduled注解就能飞速创建定时任务。

    在配置类上或启动类上添加@EnableScheduling 注解,开启任务调度。

    @Configuration
    @EnableScheduling
    public class Config {
    }
    
    • 1
    • 2
    • 3
    • 4

    @Component类中,使用方法创建任务,然后添加@Scheduled,配置cron 表达式,一个简单的任务就编写完成了:

    @Component
    public class TestTask {
    
        // 每两秒钟执行一次
        @Scheduled(cron = "*/2 * * * * ?")
        public void test() throws InterruptedException {
            // 任务处理逻辑
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    @Scheduled注解可配置的属性如下:

        @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Repeatable(Schedules.class)
        public @interface Scheduled {
            String CRON_DISABLED = "-";
            // cron 表达式
            String cron() default "";
            // 解析 cron 表达式的时区。 默认:""(即使用服务器的本地时区)。
            String zone() default "";
            // 在上次调用结束和下一次调用开始之间的固定时间段,单位:毫秒,默认:-1(不延迟)
            long fixedDelay() default -1L;
            // 上次调用的结束和下一次调用的开始之间固定时间间隔字符串,单位:毫秒。
            String fixedDelayString() default "";
            // 在调用之间的固定时间段
            long fixedRate() default -1L;
            // 在调用之间的固定时间段字符串
            String fixedRateString() default "";
            // 在第一次执行 fixedRate 或 fixedDelay 任务之前延迟的毫秒数。
            long initialDelay() default -1L;
            // 在第一次执行 fixedRate 或 fixedDelay 任务之前延迟的毫秒数字符串。
            String initialDelayString() default "";
            // 时间单位
            TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    如果使用这种方式,此时所有定时任务都在一个线程中执行。可以在以下代码执行中看出,这两个任务的线程ID 和名称都是同一个。
    在这里插入图片描述
    这样肯定就会存在问题,如果上一个任务没有执行完毕,下一个任务就算到了执行时间,也会一直处于阻塞状态。这样就很容易出现任务执行延迟,甚至丢失任务。

    所以Spring 提供了线程池去调度任务,每个任务分配单独的线程去执行,Spring Boot也提供了其自动配置功能。

    自动配置

    代码很简单,就是两个属性配置类,和两个自动配置类,从名字上就可以看出,分别为任务执行器和任务调度器,任务调度线程 调度任务执行线程 执定时任务。
    在这里插入图片描述
    自动配置主要是帮我们注册了两个Bean 对象,一个是任务调度线程池。在这里插入图片描述
    另外一个是任务执行线程池。
    在这里插入图片描述

    多线程异步任务

    为了解决单线程任务的阻塞问题,接下我们使用Spring Boot为我们提供了自动配置线程池实现多线程异步任务。

    首先在配置文件中添加线程池的配置,实际开发中要根据定时任务的数量、间隔时间、服务器性能来合理配置。

    spring:
      task:
        #  任务调度线程池
        scheduling:
          pool:
            # 任务调度线程池大小 默认 1
            size: 5
          #  调度线程名称前缀,默认scheduling-
          thread-name-prefix: scheduling-
          shutdown:
            # 线程池关闭时等待所有任务完成,默认
            await-termination: true
            # 线程关闭前最大等待时间
            await-termination-period: 100s
        # 任务执行线程池
        execution:
          pool:
            # 核心线程数
            core-size: 8
            # 最大线程数
            max-size: 16
          thread-name-prefix: mytask-
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在配置类或启动类上添加@EnableAsync注解,在任务方法上添加@Async注解。

    可以看到,就算任务执行需要3 S,实际只要时间一到就会异步多线程去执行,不会存在阻塞导致任务延迟问题。
    在这里插入图片描述
    然而,在现在微服务盛行的时代,Spring 任务无法提供分布式,只适用于一些简单的单机任务。

  • 相关阅读:
    推特营销引流入门指南
    java之《浅入了解异常》适合预习,复习
    Qt实现文本编辑器(一)
    c++11 入门基础
    线性代数的学习和整理17:向量空间的基,自然基,基变换等(未完成)
    低代码开发不可能取代程序员
    基于qt软件的网上聊天室软件
    leetcode21合并两个有序链表
    PostgreSQL 修改数据库用户的密码
    SpringCloudAliBaba(四)之Feign介绍及应用
  • 原文地址:https://blog.csdn.net/qq_43437874/article/details/125975976