天天看点

Spring Task 定时任务1. 定时任务方案2. Spring Task 串行任务3. Spring Task 并行任务

文章目录

  • 1. 定时任务方案
  • 2. Spring Task 串行任务
    • 2.1 编写任务类
    • 2.2 串行任务测试
    • 2.3 @Scheduled 所支持的参数
    • 2.4 cron 表达式
  • 3. Spring Task 并行任务

1. 定时任务方案

在项目中我们经常需要使用定时任务,实现定时任务的方案主要如下:

  1. 使用 JDK 的 Timer 和 TimerTask 实现

    可以实现简单的间隔执行任务,无法实现按日历去调度执行任务。

  2. 使用 Quartz 实现

    Quartz 是一个异步任务调度框架,功能丰富,可以实现按日历调度。

  3. 使用 Spring Task 实现

    Spring 3.0 后提供 Spring Task 实现任务调度,支持按日历调度,相比 Quartz 功能稍简单,但是在开发基本够用,支持注解编程方式。

2. Spring Task 串行任务

2.1 编写任务类

实现步骤:

  1. 创建任务类,并添加 @Component 注解
  2. 创建任务方法,并添加 @Scheduled 注解,指定任务执行策略
  3. 在 SpringBoot 启动类上添加注解:@EnableScheduling,开启定时任务

代码:

@Component
public class MyTask {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
    
    @Scheduled(cron = "0/5 * * * * *") // 每隔 5 秒执行一次
    public void task1() {
        System.out.println("定时任务1开始:" + sdf.format(System.currentTimeMillis()));
        try {
            Thread.sleep(3000); // 定时任务执行 3 秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("定时任务1结束:" + sdf.format(System.currentTimeMillis()));
    }
    
    
}
           

运行结果:

定时任务1开始:2020/10/16 05:03:40
定时任务1结束:2020/10/16 05:03:43
定时任务1开始:2020/10/16 05:03:45
定时任务1结束:2020/10/16 05:03:48
定时任务1开始:2020/10/16 05:03:50
定时任务1结束:2020/10/16 05:03:53
...
           

2.2 串行任务测试

参考 task1 方法的的定义方法,再定义 task2 方法,此时共用两个任务方法。

代码:

@Component
public class MyTask {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");

    @Scheduled(cron = "0/5 * * * * *") //每隔 5 秒执行一次
    public void task1() {
        System.out.println("定时任务1开始:" + sdf.format(System.currentTimeMillis()));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("定时任务1结束:" + sdf.format(System.currentTimeMillis()));
    }

    @Scheduled(cron = "0/5 * * * * *") //每隔 5 秒执行一次
    public void task2() {
        System.out.println("定时任务2开始:" + sdf.format(System.currentTimeMillis()));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("定时任务2结束:" + sdf.format(System.currentTimeMillis()));
    }
    
}
           

运行结果:

定时任务1开始:2020/10/16 05:11:00
定时任务1结束:2020/10/16 05:11:03
定时任务2开始:2020/10/16 05:11:03
定时任务2结束:2020/10/16 05:11:06
定时任务1开始:2020/10/16 05:11:06
定时任务1结束:2020/10/16 05:11:09
定时任务1开始:2020/10/16 05:11:10
定时任务1结束:2020/10/16 05:11:13
定时任务2开始:2020/10/16 05:11:13
定时任务2结束:2020/10/16 05:11:16
...
           

2.3 @Scheduled 所支持的参数

  • cron:cron 表达式,指定任务在特定时间执行
  • fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为 long,单位 ms
  • fixedDelayString:与 fixedDelay 含义一样,只是参数类型变为 String
  • fixedRate:表示上一次任务执行开始后多久再次执行,参数类型为 long,单位 ms
  • fixedRateString: 与 fixedRate 的含义一样,只是将参数类型变为 String
  • initialDelay:表示延迟多久再第一次执行任务,参数类型为 long,单位 ms
  • initialDelayString:与 initialDelay 的含义一样,只是将参数类型变为 String
  • zone:时区,默认为当前时区,一般没有用到

2.4 cron 表达式

cron 表达式包括 6 部分:

  • 秒(0~59)
  • 分钟(0~59)
  • 小时(0~23)
  • 月中的天(1~31)
  • 月(1~12)
  • 周中的天(填写 1~7,或 Mon、TUE 等)

特殊字符介绍:

  • “/” 字符表示指定数值的增量
  • “*” 字符表示所有可能的值
  • “-” 字符表示区间范围
  • “,” 字符表示列举
  • “?” 字符仅被用于月中的天和周中的天两个子表达式,表示不指定值(也就是月中的天和周中的天只能保留一个,另一个用 ? 表示不指定值)

例子:

  • 0/3 * * * * * 每隔3秒执行
  • 0 0/5 * * * * 每隔5分钟执行
  • 0 0 0 * * * 表示每天0点执行
  • 0 0 12 ? * WEN 每周三12点执行
  • 0 15 10 ? * MON-FRI 每月的周一到周五10点15分执行
  • 0 15 10 ? * MON,FRI 每月的周一和周五10点15分执行

3. Spring Task 并行任务

Spring Task 默认是单线程的,上面的两个定时任务使用的都是同一个线程,所以会串行执行任务。但有时我们也需要并行执行多个不同的任务,这时就需要使用多线程技术了,我们可以配置线程池来实现多线程调度任务。

代码:

  1. 创建配置类,创建线程池对象并将其加入 IOC 容器
    @Configuration
    @EnableScheduling
    public class ScheduleConfig {
        @Bean
        public ThreadPoolTaskScheduler taskScheduler() {
            ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
            scheduler.initialize(); //初始化线程池
            scheduler.setPoolSize(2); //线程池容量
            return scheduler;
        }
    }
               
  2. 任务类不变
    @Component
    public class MyTask {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
    
        @Scheduled(cron = "0/5 * * * * *") //每隔 5 秒执行一次
        public void task1() {
            System.out.println("定时任务1开始:" + sdf.format(System.currentTimeMillis()));
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("定时任务1结束:" + sdf.format(System.currentTimeMillis()));
        }
    
        @Scheduled(cron = "0/5 * * * * *") //每隔 5 秒执行一次
        public void task2() {
            System.out.println("定时任务2开始:" + sdf.format(System.currentTimeMillis()));
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("定时任务2结束:" + sdf.format(System.currentTimeMillis()));
        }
        
    }
               
  3. 将 @EnableScheduling 添加到此配置类上,SpringBoot 启动类上不用再添加 @EnableScheduling

运行结果:

定时任务2开始:2020/10/16 11:52:10
定时任务1开始:2020/10/16 11:52:10
定时任务1结束:2020/10/16 11:52:13
定时任务2结束:2020/10/16 11:52:13
定时任务2开始:2020/10/16 11:52:15
定时任务1开始:2020/10/16 11:52:15
...
           

继续阅读