一、引言
???????? 在开发过程中,我们往往需要实现一些定时功能比如执行定时任务、定时发送统计数据等,现在虽然有java有很多类似Saturn(唯品会自主研发的分布式的定时任务的调度平台),但是在一些比较小的项目而又没有搭建好的分布式定时任务中台时,可以使用Schedule定时任务框架,使用起来简单而且就算分布式项目也可以通过使用分布式锁将Schedule实现分布式定时任务功能。
二、Schedule定时框架的使用
1、添加依赖
????????使用IDEA的Spring Initiallzr创建的SpringBoot 的最基本的依赖就包含了Schedule的依赖,无需引入其它依赖了。
2、在Springboot启动类上添加@EnableScheduling注解
package com.example.schedule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@SpringBootApplication
public class ScheduleApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduleApplication.class, args);
}
}
3、根据需要选择Schedule (fixedRate、fixedDelay、cron表达式)三种任务调度器对应的具体调度器
????????3.1?fixedRate调度器(固定频率任务)
???????????@Scheduled(fixedRate = 3000)是上次任务开始的时候计时3秒后再次执行任务(这3秒包含了任务执行所需时间,即不用等待上一次调用完成,如果上次任务执行超过3秒就可能会存在任务重复执行的问题) ,但是这里要注意的是Schecule默认是单线程执行的,如果没设置Schecule并发执行任务的话,使用fixedRate依旧串行执行的,不会催在重复执行情况。
package com.example.schedule.schedule;
import cn.hutool.core.date.DateUtil;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTask {
@Scheduled(fixedRate = 3000)
public void fixedRateTest1() {
System.out.println("fixedRate : " + DateUtil.now());
}
}
?未设置并发fixedRate执行情况(这时候虽然设置是3秒间隔执行任务而实际间隔都是5秒):
package com.example.schedule.schedule;
import cn.hutool.core.date.DateUtil;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTask {
@Scheduled(fixedRate = 3000)
public void fixedRateTest1() {
System.out.println("fixedRateTest1 : " + DateUtil.now());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
?设置并发后fixedRate执行情况(执行间隔都是3秒):
import cn.hutool.core.date.DateUtil;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTask {
@Scheduled(fixedRate = 3000)
@Async
public void fixedRateTest1() {
System.out.println(Thread.currentThread().getName()+"<>fixedRateTest1 : " + DateUtil.now());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
?
????3.2?fixedDelay调度器(固定间隔任务)
???????????@Scheduled(fixedDelay= 3000)是指上次任务结束后再计时3秒后再次开启新的一次调用。
package com.example.schedule.schedule;
import cn.hutool.core.date.DateUtil;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTask {
@Scheduled(fixedDelay = 3000)
public void fixedRateTest1() {
System.out.println(Thread.currentThread().getName()+"<>fixedRateTest1 : " + DateUtil.now());
}
}
?
??3.3?cron表达式
???????????@Scheduled(cron = "0/3 * * * * *")是根据cron表达式执行定时任务的。
package com.example.schedule.schedule;
import cn.hutool.core.date.DateUtil;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTask {
@Scheduled(cron = "0/3 * * * * *")
public void cronTest1() {
System.out.println(Thread.currentThread().getName()+"<>cronTest1 : " + DateUtil.now());
}
}
三、Schedule其它
1、在线corn表达式生成器,可以图形化生成corn表达式:https://cron.qqe2.com/
2、?Schecule默认是单线程执行的,可以在Spring Schedule源码的org.springframework.scheduling.config.ScheduledTaskRegistrar里的scheduleTasks看到定时调度任务初始化时候初始化了一个单线程的线程池,所以在定时任务调度时候, 如果定时任务过多, 就会存在线程争抢,所以如果不设置成并发的时候当在同一时间多个任务并发执行时,任务调度器就会出现时间偏移,任务执行时间将不再和设置执行的一样。
?
|