一、介绍
Quartz出色的定时任务调度框架,事实上Java语言关于任务调度方面的API标准。
二、基础使用
2.1 快速使用
快速上手可帮助用户快速体验Quartz定时调度框架,无需关注配置细节。
2.1.1 新建项目
新建标准的SpringBoot项目,并导入主要依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
<version>2.6.5</version>
</dependency>
2.1.2 新建Job
测试代码
public class DemoJob implements Job {
@Override
public void execute(JobExecutionContext context) {
System.out.println("简单执行一下,不获取参数,不输出结果" + LocalDateTime.now());
}
}
2.1.3 新建配置类
@Configuration
public class QuartzConfig {
public static final String JOB_NAME = "syncUserJobDetail";
public static final String TRIGGER_NAME = "syncUserJobTrigger";
/**
* 绑定任务详情
*/
@Bean(JOB_NAME)
public JobDetail jobDetail() {
return JobBuilder.newJob(DemoJob.class).withIdentity(JOB_NAME).storeDurably().build();
}
/**
* 绑定触发器
*/
@Bean(TRIGGER_NAME)
public Trigger trigger() {
//每隔5秒执行一次
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
.cronSchedule("0/5 * * * * ?");
//创建触发器
return TriggerBuilder.newTrigger().forJob(jobDetail()).withIdentity(TRIGGER_NAME)
.withSchedule(cronScheduleBuilder).build();
}
}
完整代码仓库项目地址:
git clone https://gitee.com/java-spring-demo/quartz-demo.git
2.2 配置详解
2.2.1 调度器配置
调度器一般除了修改名称外,使用默认配置即可。
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.instanceid: AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
2.2.2 线程池配置
任务的调度是通过线程池来实现的,因此需要配置线程池。如果被调度的任务
# 线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
# 指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
org.quartz.threadPool.threadCount: 10
# 设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority: 5
# 设置SimpleThreadPool的一些属性
# 设置是否为守护线程
# org.quartz.threadpool.makethreadsdaemons = false
# org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
# org.quartz.threadpool.threadsinheritgroupofinitializingthread=false
# 线程前缀默认值是:[Scheduler Name]_Worker
# org.quartz.threadpool.threadnameprefix=swhJobThead;
2.2.3 持久化配置
根据定时任务的需要,是否需要持久化任务到磁盘上,具体判别标准如下:定时任务是否需要高可用。如果无高可用需求,简单单节点运行,无需持久化。
2.2.3.1 默认配置
默认配置不需要持久化,相关信息存储在内存中,读写速度快。
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold: 60000
# 保存job和Trigger的状态信息到内存中的类
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
2.2.3.2 持久化到DB
Quartz支持将任务及任务调度信息持久化到数据库,实现了定时任务的高可用。当定时任务多开时,通过数据库读取任务信息,防止同一任务重复执行。
spring:
quartz:
properties:
org.quartz.jobStore.misfireThreshold: 5000
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties: true
org.quartz.jobStore.tablePrefix: QRTZ_
org.quartz.jobStore.dataSource: qzDS
org.quartz.dataSource.qzDS.driver: com.mysql.cj.jdbc.Driver
org.quartz.dataSource.qzDS.URL: jdbc:mysql://localhost:3306/quartz-demo
org.quartz.dataSource.qzDS.user: root
org.quartz.dataSource.qzDS.password: 123456
org.quartz.jobStore.isClustered: true
三、理论
3.1 并发执行
Quartz的并发执行的含义是当任务的调度间隔小于任务的执行耗时时,是否执行。
一般来说在设置定时任务时尽量避免此种情况发生,然后任务在实际执行过程中,可能会偏离正常执行耗时,此时需要从机制上保证同一任务,只有在上一次调度完成后,方进行下一次调度。
通过注解DisallowConcurrentExecution禁止任务并发执行。
@DisallowConcurrentExecution
public class DemoJob implements Job {
@Override
public void execute(JobExecutionContext context) {
}
}
3.2 幂等性
在编写定时任务时,一般尽量满足幂等性原则:任务执行一次或者执行多次的效果是一致的。比如编写定时任务,将商品表转换成Redis版的BitMap,此时任务满足幂等性原则。
幂等性有助于消除任务失败重试带来的负面影响。