spring boot定时任务解析
在SpringBoot中定时任务一般使用的是@Scheduled注解。
@Scheduled
1.注解内容:
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
String CRON_DISABLED = "-";
String cron() default "";
String zone() default "";
long fixedDelay() default -1L;
String fixedDelayString() default "";
long fixedRate() default -1L;
String fixedRateString() default "";
long initialDelay() default -1L;
String initialDelayString() default "";
}
2.注解说明
@Target:表示@Schduled可以被使用在方法和注解上。
@Retention:表示@Schduled的生命周期是在程序运行时。
@Repeatable:表示@Schduled可以被在同一个地方重复使用多次,参数存放在Schedules类中(我们可以点进去看Schedules类,发现里面有一个Scheduled数组对象,用来保存多个Scheduled的配置)。
3.注解属性
String CRON_DISABLED:定时禁用标志。
String cron():定义定时执行时间,默认值"",表示该值无效。
String zone():定义时区,默认值""。
long fixedDelay():定义任务下次开始执行的间隔时间,从上一次任务执行完成开始计算,单位毫秒。默认值-1L,表示该值设置无效。
String fixedDelayString():定义任务下次开始执行的间隔时间,从上一次任务执行完成开始计算,单位毫秒。与fixedDelay不同只在于值的格式。默认值"",表示该值设置无效。
long fixedRate():定义每两次任务的间隔频率,从上一次任务开始执行开始计算,单位毫秒。默认值-1L,表示该值无效。
String fixedRateString():定义每两次任务的间隔频率,从上一次任务开始执行开始计算,单位毫秒。与fixedRate不同只在于值的格式。默认值"",表示该值无效。
long initialDelay():定义第一次执行的延迟执行时间,单位秒。默认值-1L,表示没有延迟。
String initialDelayString():定义第一次执行的延迟执行时间,与initialDelayDelay()不同在于这里使用表达式,而不是以秒为单位。默认值"",表示没有延迟。
4.样例说明
4.1 corn
@Scheduled(cron="0/2 * * * * *") //从0秒开始,每间隔2秒执行一次,参数说明在5,这里只要知道这个意思就行。
public void scheduling2() {
System.out.println("开始休眠" + new Date());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束休眠" + new Date());
}
上面例子中,我们配置了corn属性,令该任务每两秒执行一次,但是在方法体中我们又设定了方法的执行至少需要5秒。因此当定时任务开始执行下一次任务的时候,上一次任务仍然没有执行结束,时间上会存在一个冲突,我们查看控制台输出的结果是如下:
开始休眠Tue Jul 09 15:54:58 CST 2019
结束休眠Tue Jul 09 15:55:03 CST 2019
开始休眠Tue Jul 09 15:55:04 CST 2019
结束休眠Tue Jul 09 15:55:09 CST 2019
从结果可以看到,任务之间的时间间隔并不是我们指定的2秒执行一次,而是变成了6秒。这既不是我们指定的任务间隔2秒,也不是我们指定的任务执行时长5秒。
我们总结一下规律可以发现:使用corn指定时间,指定的不是任务之间的间隔时间,而是任务的开始执行时间。即我们如上配置,是指当时间在0秒,2秒,4秒……58秒的时候,会尝试开始执行任务。如果发现上一次任务没有执行结束,那么本次不会启动新的任务,同时跳过本次执行,等待下次时间达到。
由此,我们不难发现出现上面结果的原因,第一次开始执行是在54:58,第二次到达时间是55:00,此时由于任务仍没有结束,因此跳过本次执行。再下一次时间到达55:02,这时候任务仍然没有结束,继续跳过。当时间到达55:03时,任务结束,打印我们的输出语句,再然后达到下一次的任务启动时间55:04,这时上一次任务已经执行完成,重新启动新一次的任务。
4.2fixedDelay、fixedDelayString
@Scheduled(fixedDelay = 2000) //每2秒执行一次
//@Scheduled(fixedDelayString="2000") //意义同上,每两秒执行一次
public void scheduling2() {
System.out.println("开始休眠" + new Date());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束休眠" + new Date());
}
在这里,我们配置了fixedDelay属性,令任务每2秒执行一次,同时方法体中又设定了执行时间需要5秒。我们查看一下输出结果:
开始休眠Tue Jul 09 16:29:21 CST 2019
结束休眠Tue Jul 09 16:29:26 CST 2019
开始休眠Tue Jul 09 16:29:28 CST 2019
结束休眠Tue Jul 09 16:29:33 CST 2019
与corn不同的是,这里不是指定某个时间开始执行任务,而是计算每两次任务之间的时间间隔,且是从上一次任务执行结束的时间开始计算。
即假如任务完成需要5秒,设置间隔时间2秒,那么下一次任务的执行时间应该是7秒后开始执行。
4.3fixedRate、fixedRateString
@Scheduled(fixedRate = 2000) //每2秒执行一次。
//@Scheduled(fixedRateString="2000") //每2秒执行一次
public void scheduling2() {
System.out.println("开始休眠" + new Date());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束休眠" + new Date());
}
在这里我们配置了fixedRate属性,设定每2秒执行一次,但是方法体中同样设定了任务执行需要5秒。我们查看输出结果:
开始休眠Tue Jul 09 15:59:50 CST 2019
结束休眠Tue Jul 09 15:59:55 CST 2019
开始休眠Tue Jul 09 15:59:55 CST 2019
结束休眠Tue Jul 09 16:00:00 CST 2019
与corn和fixedDelay不同的是,从结果上看fixedRate是在我们方法体执行完成后,立即开始执行下一次的任务。这只是因为我们的方法执行时间大于设定的间隔时间,其实也就是说,fixedRate的间隔是从任务开始执行时候计算,但是由于间隔时间已到,但任务仍未执行完成,需要等待任务执行完成后,才立即执行下一次任务。
即下次任务的执行时间=当前时间+(执行频率 > 当前任务的执行时间 ? 执行频率 : 当前任务的执行时间)
例如:每次任务执行需要5s,fixedRate设定每2秒执行一次,第一次执行时间10:00:00,那么第二次任务执行时间=10:00:00+(2 > 5 ? 2 : 5)=10:00:05
4.4initialDelay、initialDelayString
这两个字段通常用来配合corn、fixedRate、fixedDelay进行设置。指定程序开始运行时的第一次执行的延迟时间。
例如设置initialDelay=10*1000,表示任务会在程序启动10秒后第一次运行(默认是程序启动后立即运行)。
5.参数格式
这里的参数格式主要说的是corn的格式,因为其他的属性都可以用long类型来作为以毫秒为单位的时间参数。
corn=1 * * * * * *
corn后可以以" "空格为间隔添加7个参数,从左至右依次表示:
- 秒:取值范围0-60
- 分:取值范围0-60
- 时:取值范围0-23
- 日:取值范围1-31
- 月:取值范围1-12
- 星期:取值范围1-7,同时也可以以星期的英文缩写,如周日sun
- 年:取值范围1970-2099,这个值可以省略不写。
除了直接用数字表示外,也可以使用通配符"*,?-/"
- *:表示可以取任意值,如2 * * * * *,表示每分钟的第二秒执行任务
- ,:表示多个取值,如3,6,9 * * * * *,表示每分钟的第3秒,第6秒,第9秒都会执行任务。
- ?:只能使用在日期和星期上,表示值不确定,和*差不多。
- -:表示时间范围,如0-30 * * * * *,表示每分钟的前30秒每秒执行一次。
- /:表示时间段,一般是x/y格式,x表示起始时间,y表示步长,如0/2 * * * * *,表示从0开始,每两秒执行一次任务。
6.corn、fixedDelay、fixedRate区别
定义:
corn:定义任务在某个/某些特定的时间点执行,以指定的时间为准,而不是任务。例如每周一早上8点零五分执行程序,corn=0 5 8 * * 1。
fixedDelay:定义任务下一次开始执行的时间间隔,以任务执行时间为准。即本次任务执行完成后,到下次任务开始执行前的时间间隔。从任务执行完成开始计算时间。
fixedRate:定义任务每隔多久执行一次,以任务执行时间为准。即任务开始执行后,到下次任务开始执行前的时间间隔。从任务开始执行开始计算时间。
应用场景:
corn:多应用在某个特定的时间点/段开始执行的某些任务。
fixedDelay:多应用在某些需要循环执行的任务。一般用在单任务场景,或必须要前一个任务执行完成,才能执行后一个任务的场景。
fixedRate:多应用在某些需要循环执行的任务。一般用在多任务场景,配合线程池,当时间间隔达到,就将任务丢给线程池去执行,可以同时运行任务多次,任务与任务之间互不干扰。
结束。
spring boot定时任务解析的更多相关文章
- Spring Boot定时任务应用实践
在Spring Boot中实现定时任务功能,可以通过Spring自带的定时任务调度,也可以通过集成经典开源组件Quartz实现任务调度. 一.Spring定时器 1.cron表达式方式 使用自带的定时 ...
- Spring Boot (十一): Spring Boot 定时任务
在实际的项目开发工作中,我们经常会遇到需要做一些定时任务的工作,那么,在 Spring Boot 中是如何实现的呢? 1. 添加依赖 在 pom.xml 文件中只需引入 spring-boot-sta ...
- spring boot.定时任务问题记录(TaskScheduler/ScheduledExecutorService异常)
一.背景 spring boot的定时任务非常简单,只需要在启动类中加上@EnableScheduling注解,然后在对应的方法上配置@Scheduled就可以了,系统会自动处理并按照Schedule ...
- (14)Spring Boot定时任务的使用【从零开始学Spring Boot】
本文介绍在 Spring Boot 中如何使用定时任务,使用非常简单,就不做过多说明了. com.kfit.base.scheduling.SchedulingConfig: package com. ...
- Spring Boot 定时任务单线程和多线程
Spring Boot 的定时任务: 第一种:把参数配置到.properties文件中: 代码: package com.accord.task; import java.text.SimpleDat ...
- Spring Boot 定时任务 @Scheduled
项目开发中经常需要执行一些定时任务,比如在每天凌晨,需要从 implala 数据库拉取产品功能活跃数据,分析处理后存入到 MySQL 数据库中.类似这样的需求还有许多,那么怎么去实现定时任务呢,有以下 ...
- Spring Boot @EnableAutoConfiguration解析
刚做后端开发的时候,最早接触的是基础的spring,为了引用二方包提供bean,还需要在xml中增加对应的包<context:component-scan base-package=" ...
- Spring Boot定时任务运行一段时间后自动关闭的解决办法
用Spring Boot默认支持的 Scheduler来运行定时任务,有时在服务器运行一段时间后会自动关闭.原因:Schedule默认是单线程运行定时任务的,即使是多个不同的定时任务,默认也是单线程运 ...
- Spring Boot Redis 解析
redis使用示例 本示例主要内容 使用lettuce操作redis redis字符串存储(RedisStringController.java) redis对象存储(RedisObjectContr ...
随机推荐
- 思维构造,建图——cf1159E
很好的题 /* nexti:pi右边第一个比pi大的数的下标 把每个[i,a[i]]都看成一段区间,区间只能在端点处交叉,以此来判断是否有解 特别的,如果a[i]=-1,那么把a[i]=i+1,不对其 ...
- python 版本配置问题
环境变量里有anaconda 但是命令行输入python却并不是anaconda里的python 这个现象的产生是由于anaconda在环境变量里的顺序靠后,python2.7已经在其他环境变量里被找 ...
- Docker系列(十五):Openshift 简介
1.简单了解openshift相关组件 1.openshift是基于容器技术构建的一个云平台 2.kubernetes是容器编排组件 3.docker是容器引擎驱动组件 4.openshift在Pas ...
- hdu 1754 I Hate It (线段树)
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754 线段树的模板题,详细的都写在代码里了 //不知道为什么定义单个字符,用%c输入会超时,换成字符数 ...
- python3-常用模块之os
os模块,os是和操作系统交互的模块 os.getcwd() :获取当前工作目录,即当前python脚本工作的目录路径,如果是命令行模式下,同样表示当前目录下 os.listdir(路径): 列出指定 ...
- HBase 物理视图
- HBase访问接口
- Mybatis的插件 PageHelper 分页查询使用方法
参考:https://blog.csdn.net/ckc_666/article/details/79257028 Mybatis的一个插件,PageHelper,非常方便mybatis分页查询,国内 ...
- 动态规划——DP算法(Dynamic Programing)
一.斐波那契数列(递归VS动态规划) 1.斐波那契数列——递归实现(python语言)——自顶向下 递归调用是非常耗费内存的,程序虽然简洁可是算法复杂度为O(2^n),当n很大时,程序运行很慢,甚至内 ...
- golang Linux下编译环境搭建
1.下载golang1.4和1.10源码(1.4以后的版本都用1.4go编译安装,所以先安装1.4) 2.解压后我的目录结构是: /opt/xxx/golang |-------gopath ...