一文搞定Spring Task

今天和大家分享下Spring Task这个知识点,主要通过下面6个点来展开描述,希望能够帮助到大家。

1、什么是定时任务

2、入门案例

3、Corn表达式

4、Corn实战案例

5、@Scheduled

6、多线程任务

1、什么是定时任务

定时任务是系统在特定时间执行一段代码。

定时任务的实现主要有以下几种方式:

  • Java自带的java.util.Timer类。它允许调度一个java.util.TimerTask任务,使用这种方式可以让程序按照某一个频度执行,但不能在指定时间运行,一般运用较少。
  • Quartz。是一个功能比较强大的调度器,可以让程序在执行时间执行,也可以按照某个频度执行,配置起来有点复杂。
  • Spring3.0以后自带Spring Task。可以看成一个轻量级的Quartz,

2、入门案例

1、创建SpringBoot项目在启动类开启定时任务@EnableScheduling

@SpringBootApplication
@EnableScheduling
public class SpringtaskdemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringtaskdemoApplication.class, args);
    }

}
//每秒都执行一次
@Scheduled(cron = "* * * * * *")
    public void test(){
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        System.out.println(format.format(new Date()));
    }

3、Corn表达式

Spring Task 依靠Corn表达式配置定时规则,Corn表达式是一个字符串,分为6或7个域。每个域代表一个含义,以空格隔开,有如下两种语法格式:

1、秒 分 时 每月第几天 月份 周几 年份

2、秒 分 时 每月第几天 月份 周几

3.1 秒

Seconds(秒)域可以出现,- * /0-59的整数

  • *:表示匹配该域的任意值,在Seconds域中使用 * 表示每秒钟都会出发

  • ,:表示列出枚举值,在Seconds域中使用5,20表示在5秒和20秒各触发一次

  • -:表示范围,在secondes域使用5-20,表示从5秒到20秒每秒触发一次

  • /:表示起始时间开始触发,然后每隔固定时间触发一次,在secondes域中使用5/20,表示第5秒触发一次,25秒、45秒各触发一次。

3.2 分、时

以上四个字符在minutes和Hours域都可以出现。分钟整数为0-59,小时整数为0-23

3.3 日期

DayofMonty(日期):域中可以出现,- * / ? L W C 八个字符,以及1-31的整数。

  • c:表示和当前日期相关联,如果在该域使用5c ,则在执行当天的5日后执行,且每月的那天都会执行。比如执行日是10号,则每月的15号都会触发。
  • L:表示最后,在该域使用L,表示每月的最后一天触发;
  • W:表示工作日,在该域用15W,表示在最接近本月第15天的工作日出发,如果15号是周六则14号触发,如果15号是周日则16号出发,如果15号是周二,则15号触发。 注:该用法只会在当前月计算,不会到下月触发,比如在DayofMonth域用31W,31号是周日,那么在29号触发,而不是下月1号。
  • 在DayofMonth域用LW,表示这个月的最后一个工作日触发。

3.4 月份

Month(月份):域中可出现,- * / 四个字符,以及1-12的整数或JAN-DEC的单词缩写

3.5 星期

DayofWeek(星期):可出现,- * / ? L # C 八个字符,以及1-7的整数或SUN-SAT单词的缩写,1代表星期天,7代表周六

  • c:在DayofWeek域使用2c,表示在启动日后的2天后触发,且每周的那天都会触发,如在周一启动,那么每周三都会触发;
  • L:L表示一周的最后一天(周六)触发,如果使用5L,表示在一个月的最后一个周四触发
  • :用来执行具体的周数,#前面代表星期几,#后面代表一个月的第几周。如5#3表示一个月第三周的星期四

  • ?:在无法确定是哪一天时使用。用于DayofMonth和DayofWeek域。如每个21号零点触发1次,此时无法确定21号是周几,就写 0 0 0 21 * ?

3.6 年份

Year(年份):,- * / 四个字符,以及 1970~2099的整肃,该域可以省略,表示每年都会触发。

4、Corn实战案例

每间隔5分钟触发一次 :0 0/5 * * * *
     每小时触发一次 0 0 * * * *
     每天7:30触发 0 30 7 * * *
     每周一到周五早上6:30触发  0 30 6 ? * 2-6
     每月最后一天早上10点触发 0 0 10 L * ?
     每月最后一个工作日的18:30分触发 0 30 18 LW * ?
     2030年8月每个星期六和星期日早上10触发 0 0 10 ? 8 7,1 2030
     每天10点、12点、14点触发 0 0 10,12,14 * * *
     朝九晚五工作日内每半小时触发一次 0 0/30 9-17 W * ?
     
     每周三中午12点触发一次 0 0 12 ? * 4
     每天12点触发一次 0 0  12 * * *
     每天14点到14:59每分钟触发一次 0 *  14 * * *
     每天14点到14:59每5分钟触发一次 0 0/5 14 * * *
     每天14点到14:05每分钟触发一次 0 0-5 14 * * *
     每月15日上午10:15触发  0 15 10 15 * ?
     每月最后一天的上午10:15触发 0 15 10 L * ?
     每月的第三个星期五上午10;15触发 0 15 10 ? * 6#3

5、Spring Tash @Scheduled

@Scheduled指定方法定时执行

@Scheduled写在方法上方,指定该方法定时执行,常用参数如下:

  • cron :cron制定方法执行的时间规则
  • fixedDelay :任务立即执行,之后每隔多久就执行一次,单位是毫秒,上次任务结束后计算下次执行的时间
//立即执行,任务结束后每5秒执行一次
    @Scheduled(fixedDelay = 5000)
    public void task2() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(1000);
        System.out.println(format.format(new Date()));

    }
  • fixedRate:任务立即执行,之后每隔多久就执行一次,单位毫秒,上次任务开始后开始计时
//立即执行,任务开始后每5秒执行一次
@Scheduled(fixedRate = 5000)
    public void task3() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(1000);
        System.out.println(format.format(new Date()));

    }
  • initialDelay:项目启动后不马上执行定时器,根据initialDelay 延时执行
//项目启动3s后,之后每5s执行一次
    @Scheduled(fixedRate = 5000,initialDelay = 3000)
    public void task4() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(1000);
        System.out.println(format.format(new Date()));
    }

6、Spring Task 多线程任务

Spring Task定时器默认是单线程的,如果项目中使用多个定时器,使用一个线程会造成效率低下如:

@Scheduled(cron = "* * * * * *")
    public void task5() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(5000);
        System.out.println(format.format(new Date())+Thread.currentThread().getId()+"线程任务1");
    }
    @Scheduled(cron = "* * * * * *")
    public void task6() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(5000);
        System.out.println(format.format(new Date())+Thread.currentThread().getId()+"线程任务2");
    }

解决这个问题我们可以创建一个线程池。

@Configuration
public class SchedulingConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        //创建线程池
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
    }
}

欢迎转载,转载请注明原文出处
个人公众号 :hellotqq,欢迎关注交流与您共同成长!

posted @ 2023-01-07 23:08  hellotqq  阅读(316)  评论(0编辑  收藏  举报