参考原文:https://blog.csdn.net/u011976388/article/details/85268890
一,@Schedule
SpringBoot内置了Sping Schedule定时框架,通过注解驱动方式添加所注解方法到定时任务,根据配置定时信息定时执行
二,定时任务实现
1,开启定时任务
package com.gupao.springboot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableAsync
// 开启定时任务
@EnableScheduling
@MapperScan(basePackages = {"com.gupao.springboot.*.mapper"})
public class GupaoSpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(GupaoSpringbootApplication.class, args);
}
}
2,定时任务,方法上有注释
package com.gupao.springboot.schedules;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 定时任务演示
* @author pj_zhang
* @create 2018-12-26 21:19
**/
@Component
public class ScheduleTestTask {
// 如果方法执行时间超过定时器时间, 方法执行完成后直接执行任务
@Scheduled(fixedRate = 3000)
public void test_1() {
System.out.println("fixedRate : " + new Date());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 方法执行完成后, 停留间隔时间, 再次执行该方法
// 不因为方法执行时间长度影响定时器
@Scheduled(fixedDelay = 3000)
public void test_2() {
System.out.println("fixedDelag : " + new Date());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 固定间隔时间执行, 方法执行完成后, 按照间隔时间点再次执行该方法
// 比如方法执行5s, 定时间隔为3s, 则中间有一次执行不上, 从第6s开始下一次执行
@Scheduled(cron = "0/3 * * * * *")
public void test_3() {
System.out.println("corn : " + new Date());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3,测试
* 可以看到三个线程按照线程争抢方式依次执行,与三个定时器并行不相符,原因何在? * 进入Spring Schedule源码
org.springframework.scheduling.config.ScheduledTaskRegistrar#scheduleTasks
protected void scheduleTasks() {
if(this.taskScheduler == null) {
// 从这一行可以看出, 定时调度任务初始化时候初始化了一个单线程的线程池
// 所以在定时任务调度时候, 如果定时任务过多, 就会存在线程争抢
// 而且每一次也只会有一个定时任务运行
this.localExecutor = Executors.newSingleThreadScheduledExecutor();
this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}
}
三,定时任务线程池配置
1,可以通过配置信息更改定时调度任务线程池数量
package com.gupao.springboot.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
/**
* 更改定时器线程池初始化数量配置信息
* @author pj_zhang
* @create 2018-12-26 21:27
**/
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
// 修改初始化线程数为100
scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(100));
}
}
* 执行结果,根据时间点可以看到,各个定时任务并行执行,不存在线程争抢
四,corn表达式
1,先放个大招,在线corn表达式生成器
* http://cron.qqe2.com/
2,表达式基本公式
* * * * * * * 分别对应,七个*分别对应单位为:秒,分,时,日,月,星期,年
3,字段含义
字段 取值范围 特殊字符
秒 0~59的整数 ,- * /
分 0~59的整数 ,- * /
时 0~23的整数 ,- * /
日 1~31的整数 ,- * ? / L W
月 1~12的整数 ,- * /
星期 1~7的整数或者SUN~SAT(1=SUN) ,- * ? / L #
年 1970~2099 ,- * /
* "," :表示列出枚举值,例如分钟使用5,20,则表示5和20分钟各执行一次
* "-" :表示范围,例如分钟使用5-20,表示5-20分钟每分钟触发一次
* "*" :表示匹配该域任意值,例如分钟使用*,表示每分钟都会执行一次
* "/" :表示起始时间开始触发,以后每隔多长时间触发一次,例如秒使用0/3,表示从0开始触发,后每三分钟触发一次
* "?":只能在日和星期使用,表示匹配任意值,但实际不会;因为日和星期可能会存在冲突,如果想表示每月20号0点执行,则需要写为 0 0 0 20 * ?,星期位必须写为?,虽然概念上*也表示通配
* "L" :表示最后,只出现在日和星期;例如在星期的5L,表示最后一个星期五触发
* "W" :表示有效工作日(周一-周五),只出现在日,如果指定的当天在某月刚好为周末,则就近取周五或周一执行
* "LW" :连用表示每个月最后一个星期五,只在日使用
* "#" :用于确定第几个星期的星期几,只在星期使用;例如2#3,表示在每月的第三个星期一
4,常用表达式实例
-- 0/3 * * * * ? :表示每三秒钟执行一次
-- 0 0 2 1 * ? :表示每月1号凌晨两点执行任务
-- 0 15 10 ? * MON-FRI :表示周一到周五每天早上10:15执行
-- 0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
————————————————
版权声明:本文为CSDN博主「传说中的靖哥哥」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011976388/article/details/85268890