@Scheduled 注解调度器深入解读

一、场景及背景描述
  • 在项目开发过程中,我们经常需要执行具有固定周期性的任务,比如:会员到期提醒机制、手机话费停机提醒机制等。通过定时任务可以很好的帮助我们实现这些背景的功能。

  • 常见几种定时任务比较:

    定时任务框架Cron 表达式固定间隔执行固定频率执行任务持久化开发难易度
    JDK TimerTask不支持支持支持不支持简单
    Spring Schedule支持支持支持不支持一般
    Quartz支持支持支持支持复杂

    后续文章将会给出以上所有定时器的实现方式

二、@Scheduled 注解调度器的实现
  1. 添加 Spring Boot 依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
  2. 应用主启动类添加 @EnableScheduling 注解

    /**
     * Copyright (C), 1998-2021, Shenzhen Rambo Technology Co., Ltd
     * Spring Boot Scheduled Sample 演示启动类
     *
     * @author  Rambo
     * @date    2021/02/19 17:06
     * @since   1.0.0.1
     */
    @SpringBootApplication
    @EnableScheduling
    public class SpringBootScheduleSampleApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringBootScheduleSampleApplication.class, args);
        }
    }
    
  3. 在需要实现调度任务的方法上添加 @Scheduled 注解并设置相应的调度周期即可

  4. @Scheduled 注解所支持的参数

    参数属性属性描述
    croncron表达式,指定任务在特定时间执行
    fixedDelay表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms
    fixedDelayString与fixedDelay含义一样,只是参数类型变为String
    fixedRate表示按一定的频率执行任务,参数类型为long,单位ms
    fixedRateString与fixedRate的含义一样,只是将参数类型变为String
    initialDelay表示延迟多久再第一次执行任务,参数类型为long,单位ms
    initialDelayString与initialDelay的含义一样,只是将参数类型变为String
    zone时区,默认为当前时区,一般没有用到
三、@Scheduled 注解任务调度详细说明
1、Cron 表达式的使用方式
  • 指定任务在特定时间执行
  1. 表达式定义规则

    Cron 表达式由 6 或 7 个空格分隔的时间字段组成

    位置时间域名允许值允许的特殊字符
    1秒钟0~59, - * /
    2分钟0~59, - * /
    3小时0~23, - * /
    4日期1~31, - * ? / L W C
    5月份1~12, - * /
    6星期1~7, - * ? / L C #
    7年(可选)空值 1970~2099, - * /
  2. 常用表达式

    表达式功能描述
    0/30 * * * * *每30秒执行一次
    0 0/5 * * * *每5分钟执行一次
    0 0 0 * * *每天凌晨执行一次
    0 0 9,12,18 * * *每天9点、12点、18点整执行一次
    0 30 3-5 * * *每天 3~5点 30分执行一次
  3. 添加一个 cronTest 方法,并且设置每5秒执行一次,并且每次执行耗时10秒

    /**
     * 使用 @Scheduled 注解的前提:在启动类开启了 @EnableScheduling 注解
     *
     * @author  Rambo
     * @date    2021/2/20 09:55
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void cronTest() throws InterruptedException {
        log.info("-------------> 调度线程名称:[{}],被调度方法名称:[ScheduledTasks3.cronTest()],执行频率:5秒/次,每次执行耗时10秒,当前时间:[{}]", Thread.currentThread().getName(), DateUtil.now());
        // 模拟该任务响应时间较长,导致所有采用 @Scheduled 注解调度的定时任务都被阻塞
        TimeUnit.SECONDS.sleep(10);
    }
    
  4. 当方法执行时间超过任务调度频率,调度器会在(耗时 + 调度频率)后执行,即:第一次调度任务开始到任务结束以后(无论耗时多长)这一刻开始,再重新开始计时频率

    1

2、fixedDelay & fixedDelayString 的使用方式
  • 表示上一次任务执行完成后多久再次执行
  1. 添加一个 fixedDelayTest 方法,每隔5秒执行一次,每次耗时10秒

    // @Scheduled(fixedDelay = 1000*5)
    @Scheduled(fixedDelayString = "5000")
    public void fixedDelayTest() throws InterruptedException {
        log.info("-------------> 调度线程名称:[{}],被调度方法名称:[ScheduledTasks3.fixedDelayTest()],执行频率:5秒/次,每次执行耗时10秒,当前时间:[{}]", Thread.currentThread().getName(), DateUtil.now());
        // 模拟该任务响应时间较长,导致所有采用 @Scheduled 注解调度的定时任务都被阻塞
        TimeUnit.SECONDS.sleep(10);
    }
    
  2. 当执行频率小于执行耗时都场景,下一次调度的时间是 (耗时 + 调度频率)的时间

    2

3、fixedRate & fixedRateString 的使用方式
  • 表示按一定的频率执行任务
  1. 添加一个 fixedRateTest 方法,每隔5秒执行一次,每次耗时10秒

    // @Scheduled(fixedRate = 1000*5)
    @Scheduled(fixedRateString = "50000")
    public void fixedRateTest() throws InterruptedException {
        log.info("-------------> 调度线程名称:[{}],被调度方法名称:[ScheduledTasks3.fixedRateTest()],执行频率:5秒/次,每次执行耗时10秒,当前时间:[{}]", Thread.currentThread().getName(), DateUtil.now());
        // 模拟该任务响应时间较长,导致所有采用 @Scheduled 注解调度的定时任务都被阻塞
        TimeUnit.SECONDS.sleep(10);
    }
    
  2. 效果说明

    • 如果执行频率大于执行耗时,则按照执行频率定时调度

    • 如果执行频率小于执行耗时,则下一次执行调度会在执行耗时以后立刻执行

    3

4、initialDelay & initialDelayString 的使用方式
  • 表示延迟多久再第一次执行任务
  1. 添加一个 initialDelayTest 方法,每隔5秒执行一次,每次耗时10秒

     // @Scheduled(initialDelay = 10000, fixedDelay = 5000)
    @Scheduled(initialDelayString = "10000", fixedDelay = 5000)
    public void initialDelayTest() throws InterruptedException {
        log.info("-------------> 调度线程名称:[{}],被调度方法名称:[ScheduledTasks3.initialDelayTest()],首次运行等待10秒后执行调度任务,后续频率5秒/次,当前时间:[{}]", Thread.currentThread().getName(), DateUtil.now());
        // 模拟该任务响应时间较长,导致所有采用 @Scheduled 注解调度的定时任务都被阻塞
        TimeUnit.SECONDS.sleep(10);
    }
    

    P.S

    initialDelayinitialDelayString 必须和非 cron 表达式都其它两组组合使用

  2. 效果说明

    • initialDelayinitialDelayString 必须和非 cron 表达式都其它两组组合使用
    • 首次执行按照 initialDelayinitialDelayString 预设值延迟后,后续所有频率按照其它组合都特性进行
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值