SpringBoot集成任务调度Scheduler
基础步骤
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
@EnableScheduling
public class RootConfig {
}
@Component
public class ScheduleJob {
@Scheduled(fixedRate = 2,timeUnit = TimeUnit.SECONDS)
public void testSchedule() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
System.out.println(LocalDateTime.now()+"----------");
}
}
Scheduled注解
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
String cron() default "";
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}
@Scheduled(fixedRate)如何避免任务被阻塞
加上注解@EnableAsync (类上)和@Async (方法上),加了注解以后,就开启了多线程模式,当到了下一次任务的执行时机时,如果上一次任务还没执行完,就会自动创建一个新的线程来执行它。异步执行也可以理解为保证了任务以固定速度执行。
开启多线程后,每次任务开始的间隔都是5秒钟。这是符合我们预期的,但是最后还有点缺陷,这种情况下的线程是随着任务一执行完就销毁的,等下次有需要了程序再创建一个。每次都要重新创建明显是太影响性能了,所以需要在代码里给他一个线程池。
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(5);
return taskScheduler;
}
解决线程阻塞问题
@Component
@EnableAsync
public class ScheduleJob {
@Scheduled(fixedRate = 2,timeUnit = TimeUnit.SECONDS)
@Async
public void testSchedule() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
System.out.println(LocalDateTime.now()+"----------");
}
}
执行结果如下
2022-05-07T22:20:48.117983200---------- 2022-05-07T22:20:50.072179500---------- 2022-05-07T22:20:52.067858600---------- 2022-05-07T22:20:54.067964400---------- 2022-05-07T22:20:56.067006800----------
fixedRate和fixedDelay的区别:
fixedDelay 非常好理解,它的间隔时间是根据上次的任务结束的时候开始计时的。比如一个方法上设置了fixedDelay=5*1000,那么当该方法某一次执行结束后,开始计算时间,当时间达到5秒,就开始再次执行该方法。
fixedRate 理解起来比较麻烦,它的间隔时间是根据上次任务开始的时候计时的。比如当方法上设置了fiexdRate=51000,该执行该方法所花的时间是2秒,那么3秒后就会再次执行该方法。 但是这里有个坑,当任务执行时长超过设置的间隔时长,那会是什么结果呢。打个比方,比如一个任务本来只需要花2秒就能执行完成,我所设置的fixedRate=51000,但是因为网络问题导致这个任务花了7秒才执行完成。当任务开始时Spring就会给这个任务计时,5秒钟时候Spring就会再次调用这个任务,可是发现原来的任务还在执行,这个时候第二个任务就阻塞了(这里只考虑单线程的情况下),甚至如果第一个任务花费的时间过长,还可能会使第三第四个任务被阻塞。被阻塞的任务就像排队的人一样,一旦前一个任务没了,它就立马执行。
cron表达式
通配符
单位 | 符号支持 |
---|
秒 | , - * / | 分 | , - * / | 时 | , - * / | 日 | , - * / L W | 月 | , - * / | 星期/周 | , - * / L # 只有 # 代表 周, 其他代表 星期 |
, :表示枚举,例如1,2,3
- :标识连续,例如3-5
* : 表示 每一秒、分…
/ :表示 间隔 , 例如 1/3从1秒开始每间隔3秒
L :表示最后, 例如 L
W :指定日最接近的工作日, 例如 2W
# : 指定第几周的星期几,例如 3#2 只有 # 代表 周, 其他代表 星期
? :日 或 星期 中 可以使用 ,表示 不指定
@Scheduled(cron = "1,2,3 * 22 * 5 ?")
public void testSchedule2() throws InterruptedException {
System.err.println(LocalDateTime.now()+"===========");
}
多线程
@Scheduled(cron = "* * * * * ?")
public void testSchedule3() throws InterruptedException {
System.err.println(Thread.currentThread()+"-"+LocalDateTime.now()+"\\\\\\\\");
}
spring:
task:
scheduling:
pool:
size: 5
官方参考文档
https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-annotation-support
|