首先但是任务的原理其实技就是起一个线程在指定时候去做某件事情,就不如你想在一年后控制台打印一句话你可能会这样做
Object o = new Object();
new Thread(()->{
try {
synchronized (o){
o.wait(1000*60*60*24*365);
System.out.println("一年后打印一句话。。。。。");
}
}catch (Exception e){
e.printStackTrace();
}
}).start();
是的这个方法很笨但是在抛开一切宕机及不可抗因素外这确实是一个可行的办法。
那么我来分析一下上面的写法会 有哪些问题:
1.若系统 宕机或者停电等停止服务器的行为会使打印时间不能精确的在一年后打印
2.若我们想修改成一个月后打印某一句话或者执行某一件事显然是不可能实现的
。
。
。
其实这个思路是正确的但是我们自己的实现显然过于粗糙,可用性不强。那基于这种思路市面上有了一系列的成熟解决方案。如:Quartz、Spring Scheduling 。。。。。。
今天重点记录一下Spring Scheduling 的使用。
需要强调的是Scheduling 并不是spring的一个子项目 他只是spring在3.x的时候集成的一个定时功能而已。
使用方式如下:
一:使用注解配置
1.使用springboot则默认自动集成了相关依赖。
2.在springboot启动类上添加@EnableScheduling注解
3.编写定时逻辑类,类上加@Component或者@Configuration注解将类加载到bean容器中
4.在类中编写定时逻辑方法,方法上加上@Scheduled注解,该注解的值是必填的(最少填写一个属性),值介绍如下:
String cron() default ""; //cron表达式可以定制化执行任务 例如"00 10 08 * * * ?"意思是每天的8:10:00执行该定时任务。
String zone() default ""; //设置时区
long fixedDelay() default -1L;//以一个固定long类型速率来调用一次执行 以开始结束计算
String fixedDelayString() default ""; //以一个固定long类型速率来调用一次执行 以结束时间计算
long fixedRate() default -1L; //以一个固定long类型速率来调用一次执行 以开始时间计算
String fixedRateString() default "";//以一个固定String 类型速率来调用一次执行 以开始时间计算
注意:fixedRate下一次执行时间是本次开始时间加间隔时间;而fixedDelay下一次执行时间是本次结束时间加间隔时间
long initialDelay() default -1L; //设置第一次任务启动延迟时间 和上面注解搭配使用
String initialDelayString() default ""; //设置第一次任务启动延迟时间 和上面注解搭配使用
值得注意的是cron的表达式含义如下:“* * * * * * *”
域名 可取值 可取符号(仅列部分常用)
秒域 0~59的整数 * - , /
分域 0~59的整数 * - , /
时域 0~23的整数 * - , /
日域 1~31的整数 * - , / ? L
月域 112的整数或JANDEC * - , /
周域 17的整数或SUNSAT * - , / ? L #
年域 1970~2099的整数 * - , /
符号含义如下:
1)* 表示可以匹配该域的所有值;
例如,"0 0 13 * * ?"表示每天的13点执行一次。
(2)?在cron表达式中必须出现且只能出现1次,用在日域或周域上,表示不确定值、不限制值;
它与*的区别是,并不能匹配到该域上的所有值,例如指定了3月份每个周五,那么3月份的周五可能只有4个值;
例如,"0 0 5 6 * ?"表示每个月6日5点钟执行而无论周几,"0 0 5 ? * 3"表示每个周三5点钟执行而无论是几号。
(3)- 表示匹配该域上的一个范围;
例如,"0 30 9-15 ? * *"表示每天的9:30-15:30每小时执行一次,"0 1-5 * ? * 1"表示每周日每个小时的1-5分钟每分钟执行一次。
(4), 表示枚举值;
例如,"0 0 8,16,23 ? * 1,7"表示每个周六日的8点、16点、23点各执行一次。
(5)/ 表示起始时间和间隔时间;
例如,"0 0 3/5 * * ?"表示每天3点开始执行,每隔5个小时执行一次,即3点、8点、13点、18点、23点各执行一次,
"*/5 * * * * ?"表示每隔5秒钟执行一次,"0 */1 * * * ?"表示每隔1分钟执行一次。
(6)# 只能用于周域上,#后面的数字表示第几周,如果不存在这个周的值,则不执行;
例如,"0 0 0 ? * 5#2"表示每个月第2个周四零点执行,"15 30 6 ? * 7#5"表示每个月第5个周六6:30:15执行,如果某个月不存在第5个周六,则不执行。
(7)L 只能用于日域或周域,用于日域时表示当月最后一天,用于周域如果前面不加数字表示周六,加数字表示最后一个周值;
例如,"0 0 23 L * ?"表示每月最后一天的23点执行,"0 0 23 ? * L"表示每周六的23点执行,"0 0 23 ? * 3L"表示每月最后一个周二的23点执行。
(摘抄至:https://www.cnblogs.com/dubhlinn/p/10740838.html)
5.启动项目即可生效
二丶基于接口实现
1.使用springboot则默认自动集成了相关依赖。
2.在springboot启动类上添加@EnableScheduling注解
3.编写定时逻辑类,类上加@Component或者@Configuration注解将类加载到bean容器中
4.创建一个任务定时任务类 实现 SchedulingConfigurer接口并且实现configureTasks方法
5.重写configureTasks方法,需要注意这种方法也需要用到Cron表达式,含义和上面的一样
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
//类似于Cron写法
scheduledTaskRegistrar.addTriggerTask(()->{System.out.println("CronTrigger");//具体任务
},(tigger)->{return new CronTrigger("00 * * * * ?").nextExecutionTime(tigger);//任务调度器
});
//类似于fixedRate写法
scheduledTaskRegistrar.addTriggerTask(()->{System.out.println("PeriodicTrigger");//具体任务
},(tigger)->{return new PeriodicTrigger(time).nextExecutionTime(tigger);//任务调度器
});
}
三丶定时任务的配置
问题:默认Scheduling 是单线程执行的,即当系统中某个定时任务还没执行完成的情况下若第二个定时任务条件触发需要等第一个定时任务完成才可开始执行,这样的情况就违背了定时任务的初衷
解决方案:配置多线程执行定时任务
spring.task.scheduling.pool.size=24