• 定时任务基本使用指南(cron 时间表达式、Spring 自带调度器、JDK 原生定时器)


    cron 时间表达式(七子表达式)

    cron 表达式,又称时间表达式(七子表达式),是一个字符串,以5或者6个空格隔开,字符串被切割为6个或者7个域,每个域都代表不同的含义

    // 从左到右分别表示:秒 分 时 日 月 周 年;参数以空格隔开,其中 年 不是必须参数,可以省略。
    {Seconds} {Minutes} {Hours} {DayofMonth} {Month} {DayofWeek} {Year}
    
    • 1
    • 2
    序号时间元素是否必填入参范围可填通配符
    10-59, - * /
    20-59, - * /
    30-23, - * /
    41-31, - * ? / L W
    51-12 或 JAN - DEC, - * /
    6周(周一 ~ 周日)1-7(1=SUN )
    或 SUN,MON,TUE,WED,THU,FRI,SAT
    , - * ? / L #
    81970-2099, - * /

    常用通配符:

    *	表示匹配该域的任意值,比如 Minutes 域使用 * 表示每分钟都会触发
    -	表示范围,比如 Minutes 域使用 10-20 表示从10分钟到20分钟每分钟都会触发一次
    ,	表示列出枚举值,比如 Minutes 域使用 1,3 表示1分钟和3分钟都会触发一次
    /	表示间隔时间触发(开始时间/时间间隔),例如在 Minutes 域使用 5/10 表示从第5分钟开始,每隔10分钟触发一次
    ?	表示不指定值,简单理解就是忽略该字段的值,直接根据另一个字段的值触发执行,仅被用于 DayofMonth 域和 DayofWeek 域中
        当这两个域其中之一被指定了值以后,为了避免冲突,需要将另一个域的值设为“?L	表示最后,是单词"last"的缩写(最后一天或最后一个星期几);仅被用于 DayofMonth 域和 DayofWeek 域中
        	用在 DayofMonth 域 表示该月的最后一天
        	用在 DayofWeek 域 表示一个星期的最后一天,也就是周六
        在使用'L'时,不要指定列表','或范围'-',否则易导致出现意料之外的结果
    	如果在“L”前有具体的内容,它就具有其他的含义了
    		例如:“6L”表示这个月的倒数第6天,“FRIL”表示这个月的最一个星期五
    	注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题
    #	表示该月第n个星期x(x#n),仅用 DayofWeek 域,如:6#3 表示该月的第三个星期五
    W	仅用在 DayofMonth 域中,表示距离当月给定日期最近的工作日(周一到周五),是单词"weekday"的缩写
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注意:天数和星期不能同时指定值!!!

    示例:

    // 每天凌晨零点执行
    @Scheduled(cron ="0 0 0 * * * ?")
    // 每隔五分钟执行
    @Scheduled(cron ="0 */5 * * * * ?")
    // 在每天下午2点到下午2:55期间的每5分钟触发
    @Scheduled(cron ="0 0/5 14 * * ?")
    // 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
    @Scheduled(cron ="0 0/5 14,18 * * ?")
    // 在每天下午2点到下午2:05期间的每1分钟触发
    @Scheduled(cron ="0 0-5 14 * * ?")
    // 每个星期三中午12点
    @Scheduled(cron ="0 0 12 ? * WED")
    // 每月的第三个星期五上午10:15触发
    @Scheduled(cron ="0 15 10 ? * 6#3")
    // 每年三月的星期三的下午2:10和2:44触发
    @Scheduled(cron ="0 10,44 14 ? 3 WED")
    // 每月最后一日的上午10:15触发
    @Scheduled(cron ="0 15 10 L * ?")
    // 每月的最后一个星期五上午10:15触发
    @Scheduled(cron ="0 15 10 ? * 6L")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    spring 自带调度器:@Scheduled

    介绍

    定时调度其实有很多的第三方平台可以接入,但是其实在 SpringBoot 有自带的定时任务注解 @Scheduled。@Scheduled 可以通过注解配置快速实现方法的定时调度,直接在方法加上 @Scheduled 注解即可。

    定时任务开启条件:

    • @Scheduled 标注的方法所在类交给 Spring 容器管理(即标注 Spring IOC 注解)

    • 在配置类或 @Scheduled 标注的方法所在类上添加 @EnableScheduling 注解开启定时任务功能

      @EnableScheduling 注解的作用是发现注解@Scheduled的任务并后台执行


    @Scheduled注解参数:

    • cron 参数:数据类型为 String

      最经常使用的参数,表示接收一个时间表达式(七子表达式),最多接收7个时间元素

    • zone 参数

      指定获取的时区,默认是空,表示使用服务器所在时区,比如 Asia/BeiJingi 或者 Asia/Shanghai

    • fixedDelay 参数

      指定上次执行结束后到再次执行的固定时间,单位是毫秒。

      示例:@Scheduled(fixedDelay= 3000) 表示距离上次调用后三秒再执行

    • fixedDelayString 参数

      fixedDelayString 与 fixedDelay 是几乎一样的,唯一的差异是 fixedDelayString 是支持占位符的

    • fixedRate 参数

      指定多久执行一次,单位是毫秒。与 cron 参数的 / 通配符效果相似

      示例:@Scheduled(fixedRate= 3000) 表示每三秒执行一次

    • fixedRateString 参数

      fixedRate 参数的升级,支持占位符

    • initialDelay 参数

      表示第一次延迟多少毫秒执行,单位是毫秒

      示例:@Scheduled(initialDelay= 3000) 表示第一次执行时,延迟3秒执行

    • initialDelayString 参数

      initialDelay 参数的升级,支持占位符


    注意

    若微服务是多实例部署,则每一个微服务实例都会同时执行定时调度任务,可能产生很多重复数据或者导致系统出现其他的业务逻辑BUG,所以在使用 @Scheduled 进行任务调度时,需要配合 redis 的分布式锁来使用,让定时调度任务只在一个微服务实例上执行,避免BUG出现。


    使用示例

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
     
    import java.time.LocalDateTime;
     
    @Component
    @Slf4j
    public class Task {
        
        // 每5秒执行一次
        @Scheduled(cron = "0/5 * * * * ?")
        public void task2(){
            log.warn("现在时间:" + LocalDateTime.now());
        }
        
        // 上⼀次开始执⾏时间点之后2秒再执⾏
        @Scheduled(fixedRate = 2000)
        public void task(){
            log.warn("现在时间:" + LocalDateTime.now());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    JDK 原生定时器

    介绍

    定时器,可以设置线程在某个时间执行某件事情,或者某个时间开始,每间隔指定的时间反复的做某件事情

    java.util.Timer 类:是一个描述定时器的类

    一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。

    构造方法:

    public Timer()		// 创建一个新计时器。
    
    • 1

    成员方法:

    // 终止此计时器,丢弃所有当前已安排的任务
    void cancel()
        // 注意,在此计时器调用的计时器任务的 run 方法内调用此方法,就可以绝对确保正在执行的任务是此计时器所执行的最后一个任务。
        
    // 在指定的毫秒值之后,执行指定的任务,只会执行一次
    void schedule(TimerTask task, long delay) 	
    // 在指定的毫秒值之后,执行指定的任务,之后每隔固定的毫秒数重复执行定时任务
    void schedule(TimerTask task, long delay, long period)
    // 安排在指定的时间执行指定的任务,只会执行一次
    void schedule(TimerTask task, Date time) 
    // 安排指定的任务在指定的时间开始进行重复的固定延迟执行
    void schedule(TimerTask task, Date firstTime, long period) 
    /* 参数:
    		task		所要安排的任务。定时器到时间之后要执行的任务
    		delay		执行任务前的延迟时间,单位是毫秒。 多个毫秒之后开始执行TimerTask任务
    		period		执行各后续任务之间的时间间隔,单位是毫秒。定时器开始执行之后,每隔多少毫秒重复执行
    		time		执行任务的时间。从什么日期开始执行任务  20020-07-06 15:25:13
    		period		执行各后续任务之间的时间间隔,单位是毫秒。定时器开始执行之后,每隔多少毫秒重复执行
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    TimerTask 类:由 Timer 执行的一次执行或重复执行的任务

    java.util.TimerTask implements Runnable 接口

    TimerTask 类是一个抽象类,无法直接创建

    成员抽象方法:

    // 此计时器任务要执行的操作。重写run方法,设置线程任务
    void run()
    
    • 1
    • 2

    使用示例

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class Demo01Timer {
        public static void main(String[] args) throws ParseException {
            show04();
        }
        
        /*
            在指定的毫秒值之后,执行指定的任务,只会执行一次
            void schedule(TimerTask task, long delay) 
        */
        private static void show01() {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println("c4爆炸了!");
                    timer.cancel();
                }
            }, 5000);
        }
        
        /*
            在指定的毫秒值之后,执行指定的任务,之后每隔固定的毫秒数重复执行定时任务
            void schedule(TimerTask task, long delay, long period)
         */
        private static void show02() {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Timer timer =new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println(sdf.format(new Date()));
                }
            }, 5000, 1000);
        }
        
        /*
            安排在指定的时间执行指定的任务,只会执行一次
            void schedule(TimerTask task, Date time) 
         */
        private static void show03() throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = sdf.parse("2020-07-06 15:32:50");
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println("哈哈!");
                    timer.cancel();
                }
            }, date);
        }
    
        /*
            安排指定的任务在指定的时间开始进行重复的固定延迟执行
            void schedule(TimerTask task, Date firstTime, long period) 
         */
        private static void show04() throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = sdf.parse("2020-07-06 15:37:30");
            Timer timer  = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println("嘿嘿,你中招了!");
                }
            }, date, 10);
        }
    }
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
  • 相关阅读:
    密码学 | RC4算法Native层分析
    C/C++文档编辑器
    自媒体账号如何运营赚钱?
    【线性代数】二次型总结
    商城小程序代客下单程序开发演示
    RFLA--F
    接口测试关键技术
    JAVA微服务场景下分布式日志收集排查问题实战
    【优化调度】基于matlab遗传算法求解工件的并行调度组合优化问题【含Matlab源码 2234期】
    vue;element-ui
  • 原文地址:https://blog.csdn.net/footless_bird/article/details/126679351