@Scheduled定时器

一、基本使用

@Scheduled  // 由Spring定义,用于将方法设置为调度任务。如:定时执行一次或定时轮询执行一段代码。该注解放到需要定时执行的方式上

@EnableScheduling  // 再项目启动类上添加注解@EnableScheduling,表示开启定时任务
@Scheduled(fixedDelay=20*1000)   //每隔20秒执行
public void scheduledTaskByFixedDelay() {
    log.info("定时任务开始 ByFixedDelay:" + DateUtils.getDatetimeString());
    String str = "Hello,,,World,,,每20秒,,,指定参数FixedDelay,,,";
    List<Map<String,String>> list = helloService.getTemp();
    log.info(str+ JSON.toJSONString(list));
    log.info("定时任务结束 ByFixedDelay:" + DateUtils.getDatetimeString());
}
@SpringBootApplication
@EnableScheduling
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

二、参数说明

fixedDelay

上一次任务执行完毕时间点之后多长时间再执行,任务的执行要等上一个任务执行结束。
它的间隔时间是根据上次的任务结束的时候开始计时的。
比如一个方法上设置了 fixedDelay=10*1000,那么当该方法某一次执行结束后,开始计算时间,当时间达到10秒,就开始再次执行该方法。

@Scheduled(fixedDelay=10000)   //每隔10秒执行

@Scheduled(fixedDelay=60*60*1000)   //每隔1小时执行

fixedRate

上一次任务开始执行点之后指定时间后再执行(如果执行时间超过了间隔时间,那上一次任务执行完之后,立即执行下一个任务)
fixedRate 理解起来比较麻烦,它的间隔时间是根据上次任务开始的时候计时的。比如当方法上设置了 fiexdRate=5000,该执行该方法所花的时间是2秒,那么3秒后就会再次执行该方法。
但是这里有个坑,当任务执行时长超过设置的间隔时长,那会是什么结果呢。打个比方,比如一个任务本来只需要花2秒就能执行完成,我所设置的fixedRate=5000,但是因为网络问题导致这个任务花了7秒才执行完成。当任务开始时Spring就会给这个任务计时,5秒钟时候Spring就会再次调用这个任务,可是发现原来的任务还在执行,这个时候第二个任务就阻塞了(这里只考虑单线程的情况下,多线程后面再讲),甚至如果第一个任务花费的时间过长,还可能会使第三第四个任务被阻塞。被阻塞的任务就像排队的人一样,一旦前一个任务没了,它就立马执行。

@Scheduled(fixedRate=60000)   //任务开始执行后隔60秒执行

@Scheduled(fixedRate=60*60*1000)   //任务开始执行后隔1小时执行

initialDelay

第一次任务将会延迟指定时间后启动

@Scheduled(fixedDelay=60*60*1000,initialDelay=60*1000)   //第一次任务延迟1分钟启动,之后每隔1小时执行

cron

该参数接受一个cron表达式,cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义。

@Scheduled(cron="秒 分 时 日 月 周 年")   // 年不是必需的,可省略

三、cron 表达式

@Scheduled(cron="秒 分 时 日 月 周 年")   // 年不是必需的,可省略

参数说明

其中,每个时间字段都有对应的取值范围和特殊符号。下面是每个时间字段的详细说明:

1、秒 (Seconds):取值范围为 0~59。例如,'0/5'表示每隔5秒触发一次。'*'表示每秒种都触发。允许使用特殊字符 , - * /

2、分钟 (Minutes):取值范围为 0~59。例如,'0/5'表示每隔5分钟触发一次。'*'表示每分种都触发。允许使用特殊字符 , - * /

3、小时 (Hours):取值范围为 0~23。例如,'0/2'表示每隔2小时触发一次。'*'表示每小时都触发。允许使用特殊字符 , - * /

4、日期 (Day of Month):取值范围为 1~31。例如,'1,15'表示每月的1日和15日触发,'*'表示每天都触发。允许使用特殊字符 , - * ? / L W C

5、月份(Month):取值范围为 1~12,也可以使用英文缩写JANFEBMAR等。例如,'1,6'表示一月和六月触发,'*'表示每个月都触发。允许使用特殊字符 , - * /

6、星期 (Day of Week) :取值范围为 1~71 表示星期日,2 表示星期一,以此类推,也可以使用英文缩写 SUNMONTUE 等。例如,'2-6'表示星期一到星期五触发,'*' 表示每个星期都触发。允许使用特殊字符 , - * ? / L C #

7、年份 (Year):可选字段,表示触发条件的年份。例如,'2023' 表示在2023年触发,'*' 表示每年都触发。允许使用特殊字符 , - * /

// 在使用时,由于"月份中的日期"和"星期中的日期"这两个元素互斥的,必须要对其中一个设置?

除了取值范围,Cron 表达式还支持一些特殊符号,用于指定特定的触发条件,例如:

星号(*):代表所有可能的取值,表示不限制该时间字段的取值范围。
问号(?):仅在日期和星期字段中使用,表示不指定具体的取值,可以任意匹配。
斜线(/):表示间隔触发,例如在分钟字段中,"*/5"表示每隔5分钟触发一次。"0/15"表示从第0分钟开始,每15分钟。"3/20"表示从第3分钟开始,每20分钟(它和"3,23,43")的含义一样
逗号(,):用于指定多个取值,例如在小时字段中,"1,3,5" 表示在第 135 小时触发。
减号(-):用于指定一个范围,例如在月份字段中,"3-6" 表示三月到六月触发。

"L" 字符仅被用于天(月)和天(星期)两个子表达式,它是单词"last"的缩写
如果在"L"前有具体的内容,它就具有其他的含义了。例如:"6L"表示这个月的倒数第6天
注意:在使用"L"参数时,不要指定列表或范围,因为这会导致问题
"W" 字符代表着工作日(Mon-Fri),并且仅能用于日历中。它用来指定离指定日的最近的一个星期日。大部分的商业处理都是基于工作周的,所以 W 字符可能是非常重要的。
例如,日域中的 15W 意味着 "离该月15号的最近一个工作日"。 假如15号是星期六,那么 trigger 会在14(星期五)触发,因为星期伍比星期一离15号更近。
"C" 字符代表"Calendar"的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。

实用性的案例

"0 0 10,14,16 * * ?"  每天上午10,14,16"0 0/30 9-17 * * ?"   朝九晚五工作时间内每半小时
"0 0 12 ? * WED" 表示每个星期三中午12"0 0 12 * * ?"   每天中午12点触发 
每天上午10:15触发: "0 15 10 ? * *"   "0 15 10 * * ?"   "0 15 10 * * ? *"
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发 
"0 * 14 * * ?"       在每天下午2点到下午2:59期间的每1分钟触发 
"0 0/5 14 * * ?"     在每天下午2点到下午2:55期间的每5分钟触发 
"0 0/5 14,18 * * ?"  在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 
"0 0-5 14 * * ?"     在每天下午2点到下午2:05期间的每1分钟触发 
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:102:44触发 
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 
"0 15 10 15 * ?" 每月15日上午10:15触发 
"0 15 10 L * ?"  每月最后一日的上午10:15触发 
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 
"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 


@Scheduled(cron = "*/5 * * * * ?")  \\每隔5秒钟执行一次

@Scheduled(cron = "0 */1 * * * ?")  \\每隔一分钟执行一次

@Scheduled(cron = "0 26,29,33 * * * ?")  \\在各个小时的26分、29分、33分执行一次

@Scheduled(cron = "0 0 */2 * * ?")  \\每隔两小时执行一次

@Scheduled(cron = "0 0 1 * * ?")  \\每天凌晨1点执行一次

@Scheduled(cron = "0 0 6,15,20 * * ?")  \\每天的6点、15点、20点触发定时任务

@Scheduled(cron = "0 0 2 1 * ?")  \\每月1号凌晨2点执行一次

@Scheduled(cron = "0 0 23 L * ?")  \\每月最后一天23点执行一次

@Scheduled(cron = "0 0 3 ? * L")  \\每周星期六凌晨3点执行一次

@Scheduled(cron = "0 0 12 ? * SUN")  \\每周星期天中午12点执行一次

@Scheduled(cron = "0 0 0 L * ?")  \\每个月的最后一天执行一次

@Scheduled(cron = "0 0/5 9-17 * * MON-FRI")  \\工作日的早上 9 点到下午 5 点,每隔 5 分钟触发定时任务

Scheduled(cron=“0 */1 * * * ?”)
每一分钟执行一次。比如第一次执行时间为2023-10-20 23:08:12,下一次2023-10-20 23:09:12,再下一次2023-10-20 23:10:12

@Scheduled(cron = “10 * * * * ?”)
每分钟的第十秒执行一次。比如第一次执行时间为2023-10-20 23:09:10,下一次2023-10-20 23:10:10,再下一次2023-10-20 23:11:10。 之所以用(23:09:10)举例,是因为上一个任务是在(23:08:12)才启动,所以任务只能从23:09:10开始

@Scheduled(cron = “*/10 * * * * ?”)
每十秒钟执行一次。比如第一次执行时间为2023-10-20 23:08:12,下一次2023-10-20 23:08:22,再下一次2023-10-20 23:08:32

四、@Scheduled注意事项

  • spring的注解@Scheduled 需要写在实现方法上
  • 定时器的任务方法不能有返回值(如果有返回值,spring初始化的时候会告诉你有个错误、需要设定一个proxytargetclass的某个值为true),不能指向任何的参数
  • 如果该方法需要与应用程序上下文的其他对象进行交互,通常是通过依赖注入来实现
  • 实现类上要有组件的注解@Component

五、配置文件

1、fixedDelay

@Scheduled(initialDelay = 5, fixedDelayString = "${erwin.fixed-delay:2}", timeUnit = TimeUnit.SECONDS)
public void scheduledTaskByFixedDelay() {
	log.info("定时任务开始 ByFixedDelay:" + DateUtils.getDatetimeString());
    log.info("Hello,,,World,,,指定参数fixedDelay,,,");
}

配置文件 .yml

erwin:
  fixed-delay: 5

如果在配置文件中没有配置,则每隔2秒执行一次,如果配置了,就每隔5秒执行一次。initialDelay 表示,项目启动后,5秒开始执行第一次任务。
注意:${erwin.fixed-delay:2},冒号前后不能有空格。

2、fixedRate

@Scheduled(initialDelay = 5, fixedRateString = "${erwin.fixed-rate:2}", timeUnit = TimeUnit.SECONDS)
public void scheduledTaskByFixedRate() {
	log.info("定时任务开始 ByFixedRate:" + DateUtils.getDatetimeString());
    log.info("Hello,,,World,,,指定参数fixedRate,,,");
}

配置文件 .yml

erwin:
  fixed-rate: 5

3、cron

如果配置文件没有配,就会使用默认的值。

@Scheduled(cron = "${erwin.cron:0/10 * * * * ?}")
public void scheduledTaskByCron() {
	log.info("定时任务开始 ByCron:" + DateUtils.getDatetimeString());
    log.info("Hello,,,World,,,指定参数cron,,,");
}

配置文件 .yml

erwin:
  cron: 0/30 * * * * ?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值