在项目我们会有很多需要在某一特定时刻自动触发某一时间的需求,例如我们提交订单但未支付的超过一定时间后需要自动取消订单。
定时任务实现的几种方式:
Timer:java自带的java.util.Timer类,使用这种方式允许你调度一个java.util.TimerTask任务。这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。
ScheduledExecutorService:也是jdk自带的类;基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,既任务是并发执行,互不影响。
Spring Task:Spring3.0以后自带的task,相当于一个轻量级的Quartz,但其使用起来比Quartz简单很多。
Quartz:一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂。
下面我们看一下如何通过Scheduled实现SpringBoot 的定时任务。
1. 启用定时任务
在springboot主类增加注解@EnableScheduling启用定时任务
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class ScheduledApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootScheduledApplication.class, args);
}
}
2.创建任务类
@Slf4j
@Component
public class ScheduledService {
@Scheduled(cron = "0/20 * * * * *")
public void scheduled(){
log.info("1使用cron {}",System.currentTimeMillis());
}
@Scheduled(fixedRate = 3000)
public void scheduled1() {
log.info("2使用fixedRate{}", System.currentTimeMillis());
}
@Scheduled(fixedDelay = 3000)
public void scheduled2() {
log.info("3fixedDelay{}",System.currentTimeMillis());
}
}
默认为单线程,可以看到三个定时任务都已经执行,并且使同一个线程中串行执行,如果只有一个定时任务,这样做肯定没问题,当定时任务增多,如果一个任务卡死,会导致其他任务也无法执行。
3.实现多线程任务
3.1 添加配置类并启用异步事件
@Configuration
@EnableAsync
public class ScheduledAsyncConfig {
private int corePoolSize = 20;
private int maxPoolSize = 500;
private int queueCapacity = 20;
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.initialize();
return executor;
}
}
3.2,修改2.中的定时任务的类或者方法上添加@Async
@Slf4j
@Component
@Async
public class ScheduledService {
@Scheduled(cron = "0/20 * * * * *")
public void scheduled(){
log.info("1使用cron {}",System.currentTimeMillis());
}
@Scheduled(fixedRate = 3000)
public void scheduled1() {
log.info("2使用fixedRate{}", System.currentTimeMillis());
}
@Scheduled(fixedDelay = 3000)
public void scheduled2() {
log.info("3fixedDelay{}",System.currentTimeMillis());
}
}