Timer: 这是java自带的java.util.Timer类,这个类运行你调度一个java.util.TimerTask任务。使用这种方式可以让程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。多线程并行处理定时任务,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行
ScheduledExecutorService: 也是jdk自带的一个类;是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,任务并发执行,互不影响
Spring Task: Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多所有的定时任务都在同一线程上串行,想要异步执行需要自己添加线程池
Quartz: 这是一个功能比较强大的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂
public class TestTimer {
public static void main(String[] args) {
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("task run:" + System.currentTimeMillis());
}
};
//多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行
//并不推荐使用
Timer timer = new Timer();
//安排指定的任务在指定的时间开始进行重复的固定延迟执行,这里是延时10毫秒每3秒执行一次
timer.schedule(timerTask, 10, 3000);
}
}
该方法跟Timer类似
public class TestScheduledExecutorService {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
// 参数:1.任务体,2.首次执行的延时时间
// 3.任务执行间隔,4.间隔时间单位
service.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("task ScheduledExecutorService:" + System.currentTimeMillis());
}
}, 0, 3, TimeUnit.SECONDS);
}
}
在spring boot中我们可以直接使用注解的方式来实现定时任务,非常简单,需要的依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
创建任务类
@Slf4j
@Component
public class TestSpringTask {
/**
* 通过表达式来配置任务执行时间
*/
@Scheduled(cron = "0/5 * * * * *")
public void scheduled() {
log.info("=====>>>>>使用cron:{}", System.currentTimeMillis());
}
/**
* 按一定频率执行的定时任务
*/
@Scheduled(fixedRate = 5000)
public void scheduled1() {
log.info("=====>>>>>使用fixedRate:{}", System.currentTimeMillis());
}
/**
* 功能同fixedRate,但是可以配合initialDelay属性设置任务延时执行
*/
@Scheduled(fixedDelay = 5000)
public void scheduled2() {
log.info("=====>>>>>使用fixedDelay:{}", System.currentTimeMillis());
}
}
在Application
类上添加@EnableScheduling
注解开启对定时任务的支持
@SpringBootApplication
//开启对定时任务的支持(所有的定时任务都在同一线程上串行)
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
然后启动项目查看打印
2019-04-03 11:15:10.001 INFO 9252 --- [ scheduling-1] com.lx.timer.springtask.TestSpringTask : =====>>>>>使用cron:1554261310001
2019-04-03 11:15:12.209 INFO 9252 --- [ scheduling-1] com.lx.timer.springtask.TestSpringTask : =====>>>>>使用fixedRate:1554261312209
2019-04-03 11:15:12.211 INFO 9252 --- [ scheduling-1] com.lx.timer.springtask.TestSpringTask : =====>>>>>使用fixedDelay:1554261312211
2019-04-03 11:15:15.002 INFO 9252 --- [ scheduling-1] com.lx.timer.springtask.TestSpringTask : =====>>>>>使用cron:1554261315002
可以看到三个定时任务都已经执行,并且使同一个线程中串行执行,如果只有一个定时任务,这样做肯定没问题,当定时任务增多,如果一个任务卡死,会导致其他任务也无法执行,所以我们需要修改为多线程执行
新建一个AsyncConfig类
@Configuration
//开启异步事件的支持
@EnableAsync
public class AsyncConfig {
/**
* 以下参数均从yml配置文件中获取
*/
@Value("${async.core-pool-size}")
private int corePoolSize;
@Value("${async.max-pool-size}")
private int maxPoolSize;
@Value("${async.queue-capacity}")
private int quequeCapacity;
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(quequeCapacity);
executor.initialize();
return executor;
}
}
然后再定时任务的类或者方法上添加@Async
@Slf4j
@Component
//对当前类开启异步(开启后每个方法的执行均在不同的线程中),也可以加在方法上
@Async
public class TestSpringTask {
/**
* 通过表达式来配置任务执行时间
*/
@Scheduled(cron = "0/5 * * * * *")
public void scheduled() {
log.info("=====>>>>>使用cron:{}", System.currentTimeMillis());
}
/**
* 按一定频率执行的定时任务
*/
@Scheduled(fixedRate = 5000)
public void scheduled1() {
log.info("=====>>>>>使用fixedRate:{}", System.currentTimeMillis());
}
/**
* 功能同fixedRate,但是可以配合initialDelay属性设置任务延时执行
*/
@Scheduled(fixedDelay = 5000)
public void scheduled2() {
log.info("=====>>>>>使用fixedDelay:{}", System.currentTimeMillis());
}
}
重启项目,可以看到每个任务都是在不同的线程
2019-04-03 11:19:47.020 INFO 13420 --- [ taskExecutor-4] com.lx.timer.springtask.TestSpringTask : =====>>>>>使用fixedRate:1554261587020
2019-04-03 11:19:47.024 INFO 13420 --- [ taskExecutor-5] com.lx.timer.springtask.TestSpringTask : =====>>>>>使用fixedDelay:1554261587024
2019-04-03 11:19:50.002 INFO 13420 --- [ taskExecutor-6] com.lx.timer.springtask.TestSpringTask : =====>>>>>使用cron:1554261590002
2019-04-03 11:19:52.020 INFO 13420 --- [ taskExecutor-7] com.lx.timer.springtask.TestSpringTask : =====>>>>>使用fixedRate:1554261592020
2019-04-03 11:19:52.025 INFO 13420 --- [ taskExecutor-8] com.lx.timer.springtask.TestSpringTask : =====>>>>>使用fixedDelay:1554261592025
在上面的定时任务中,我们在方法上使用@Scheduled
注解来设置任务的执行时间,并且使用3三种属性配置方式
https://blog.csdn.net/qq_33430083/article/details/89024540
添加依赖
如果SpringBoot版本是2.0.0以后的,则在spring-boot-starter中已经包含了quart的依赖,则可以直接使用spring-boot-starter-quartz依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-quartzartifactId>
dependency>
如果是1.5.9则要使用以下添加依赖:
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartzartifactId>
<version>2.3.0version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
dependency>
注意:如果项目中springboot使用的是springboot2.0以后的版本,去引用quartz
和spring-context-support
包的话,quartz任务并不会执行
public class TestQuartz extends QuartzJobBean {
/**
* 执行定时任务
* @param jobExecutionContext
* @throws JobExecutionException
*/
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("quartz task" + System.currentTimeMillis());
}
}
执行方式有两种写法一种是使用CronScheduleBuilder
类执行cron表达式
另一种是使用SimpleScheduleBuilder
类指定间隔时间
public class QuartzConfig {
@Bean
public JobDetail teatQuartzDetail() {
return JobBuilder.newJob(TestQuartz.class)
.withIdentity("testQuartz").storeDurably().build();
}
@Bean
public Trigger testQuartzTrigger() {
//使用cron表达式
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("*/5 * * * * ?");
//指定间隔时间
// SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
// //设置时间周期单位秒,也可选择其他函数
// .withIntervalInSeconds(3)
// .repeatForever();
return TriggerBuilder.newTrigger().forJob(teatQuartzDetail())
.withIdentity("testQuartz")
.withSchedule(cronScheduleBuilder)
.build();
}
}
控制台打印如下,配置成功
quartz task1554273605007
quartz task1554273610000
quartz task1554273615000
Quartz在项目启动的时候会执行,使用注解的方式会在项目启动完成后时间算起执行,少一次执行调度
https://gitee.com/fengzxia/spring-boot-timer-learn
https://juejin.im/post/5ca24fb1e51d454a490a4809?utm_source=gold_browser_extension