定时任务调度Quartz
为什么需要定时任务调度
需要使用定时任务的业务场景
- 会员到期发短信通知
- 花呗到期各种通知
- 每天定时清理某个文件系统
- 定时重启系统
做定时任务的注意点
- 触发任务的规则是什么?比如固定的时间或当某个变量的值达到指定值时
- 需要执行的任务是什么?比如发短信提醒或者重启服务器等
- 对定时任务的配置统一集中管理,不能在代码里写死,方便维护
- 支持多个任务的串行执行,比如执行完A任务后再执行B任务,执行完B任务后才能执行C任务,任务之间有先后顺序
- 自己可以控制任务的启动、中断和停止
- 要很容易集成到Spring中
- 支持多个任务的并发执行,互不干扰
定时任务框架对比
参看下面博客内容(了解,可跳过)
https://blog.csdn.net/en_joker/article/details/104407313
官网地址
http://www.quartz-scheduler.org/
quartz
英 [kwɔːts] 美 [kwɔːrts]
Quartz的意思是石英,寓意此框架能够像石英表一样精确
下面是官网介绍
What is the Quartz Job Scheduling Library?
Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java components that may execute virtually anything you may program them to do. The Quartz Scheduler includes many enterprise-class features, such as support for JTA transactions and clustering.
英语水平有限,在这里就不翻译了,大家可以自行解决。
Quartz的特点
- 用java语言编写(也有.NET版本)
- 精确到毫秒级别的任务调度
- 可以独立运行也可以集成到容器中
- 支持事务
- 支持集群
- 支持持久化
java项目中如何使用Quartz
1:引入依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
2:查看默认配置文件
默认配置文件在org.quartz包下,名称为quartz.properties。当我们没有提供同名的配置文件时,就会使用默认配置文件里面的配置。
quartz包下面往下拉就可以找到quartz.properties,由于内容太多图中没有截全
# 任务调度器属性
org.quartz.scheduler.instanceName: DefaultQuartzScheduler #调度器名称
org.quartz.scheduler.rmi.export: false#是否支持rmi导出
org.quartz.scheduler.rmi.proxy: false#是否连接到远端服务提供的scheduler
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false#是否启动job之前启动一个UserTransaction
# 线程池属性
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool #线程池实现类
org.quartz.threadPool.threadCount: 10#线程数量
org.quartz.threadPool.threadPriority: 5#优先级最大10最小1
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true#线程初始化默认为true
# 信息保存时间,默认60秒
org.quartz.jobStore.misfireThreshold: 60000
# 任务和触发器信息默认保存到内存中
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
3:创建任务Job
我们自己的任务类实现Quartz的Job接口,重写execute()方法
public class MyJob1 implements Job {
public void execute(JobExecutionContext jobExecutionContext) {
try{
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String sdfdate = sdf.format(date).toString();
System.out.println("我的第一个定时任务1:"+sdfdate);
}catch (Exception e){
e.printStackTrace();
}
}
}
4:测试
public class TestJob1 {
public static void main(String[] args) {
//1将Job包装成JobDetail
//1.1创建JobBuilder构造器
JobBuilder jobBuilder = JobBuilder.newJob(MyJob1.class);
//1.2指定任务名称和任务所在组的名称,两个合起来必须是唯一的
jobBuilder.withIdentity("job1","group1");
//1.3携带一些键值对参数
jobBuilder.usingJobData("txl","123456");
jobBuilder.usingJobData("token","789");
//1.4构建jobDetail
JobDetail jobDetail = jobBuilder.build();
//2创建触发器Trigger
//2.1创建构造器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
//2.2指定触发器名称和所在组名,两者合起来必须唯一
triggerBuilder.withIdentity("trigger1","group1");
//2.3启动触发器
triggerBuilder.startNow();
//2.4指定触发规则
triggerBuilder.withSchedule(
//使用简单触发器规则,2秒钟触发,一直重复执行
SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2)
.repeatForever()
);
//2.5构造触发器
Trigger trigger = triggerBuilder.build();
try{
//3创建任务调度器Scheduler
SchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
//4将任务和触发器组装到一起 :一个JobDetail可以绑定多个Trigger触发器1:N
scheduler.scheduleJob(jobDetail,trigger);
//5开启任务调度器
scheduler.start();
}catch (Exception e){
e.printStackTrace();
}
}
}
结果如下
扩展:可以获取运行任务时添加的参数
我们在上面构建JobDetail时携带了两个参数
//1.3携带一些键值对参数
jobBuilder.usingJobData("txl","123456");
jobBuilder.usingJobData("token","789");
其实在这里配置的参数我们可以在任务对象MyJob1里面获取到
public class MyJob1 implements Job {
public void execute(JobExecutionContext jobExecutionContext) {
try{
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String sdfdate = sdf.format(date).toString();
//获取JobDetail里面携带的参数
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
System.out.println("我的第一个定时任务1:"+sdfdate+";token="+jobDataMap.getString("token")+"; txl="+jobDataMap.getString("txl"));
}catch (Exception e){
e.printStackTrace();
}
}
}
结果如下
扩展(了解内容): jdk自定的定时任务 Timer
Timer定时任务调度只支持单线程
创建任务对象
public class MyTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("这时jdk自带的定时任务");
}
}
执行任务
public class TestTimerTask {
public static void main(String[] args) {
Timer timer = new Timer();
MyTimerTask task = new MyTimerTask();
//第一个参数为任务,第二个参数是5秒后开始执行,第三个参数是开始后每隔一秒执行一次
timer.schedule(task,5000L,1000L);
}
}
结果如下