简单说明
简单的定时任务使用Timer或者ScheduledExecutorService
quartz支持复杂的定时执行功能。支持ram存储(内存存储)和持久化存储。quartz有分布式和集群能力
简单使用
- 获取任务调度器Schedule。任务调度器可以管理任务。
- 创建任务实例。使用JobBuilder(任务类.class)创建,会返回一个JobDetail。任务是一个实现了Job,并实现execute方法的类而已,execute方法记录要执行的事情。
- 创建触发器Trigger。Trigger是用来指定触发策略的,包括什么时候开始执行、循环多少次、多久执行一次呀,等等。支持链式编程。
- 把任务和触发器告诉任务调度器,使用scheduleJob方法来完成。
- 使用任务调度器启动任务
- 使用任务调度器关闭任务
例子:
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class SimpleJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("SimpleJob is executing at: " + new java.util.Date());
}
}
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzExample {
public static void main(String[] args) {
try {
// 1. 获取任务调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2. 创建任务实例
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.withIdentity("simpleJob", "group1")
.build();
// 3. 创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("simpleTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10) // 每10秒执行一次
.repeatForever()) // 无限重复
.build();
// 4. 把任务和触发器告诉任务调度器
scheduler.scheduleJob(job, trigger);
// 5. 使用任务调度器启动任务
scheduler.start();
// 让任务运行一段时间
Thread.sleep(60000); // 60秒
// 6. 使用任务调度器关闭任务
scheduler.shutdown();
} catch (SchedulerException | InterruptedException e) {
e.printStackTrace();
}
}
}
使用了 Builder 模式(建造者模式):
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.withIdentity("simpleJob", "group1")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("simpleTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever())
.build();
Quartz基本的实现原理
- job和jobdetail的关系是什么?
Job(任务)是一个接口,表示一个具体的任务。你需要实现这个接口,并在 execute 方法中定义任务的具体逻辑。Job 只关注任务的执行逻辑,即 做什么。
JobDetail(任务详情)JobDetail 是一个类,用于描述任务的详细信息。它包含了任务的元数据,例如任务类、任务名称、任务组、任务数据等。JobDetail 关注任务的 元信息,即 谁来做 和 怎么做。
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.withIdentity("simpleJob", "group1")
.build();
这里 JobDetail 描述了任务的详细信息:
- 任务类是 SimpleJob.class。
- 任务名称是 “simpleJob”。
- 任务组是 “group1”。
总结:
- Job:定义任务的具体逻辑(做什么)。
- JobDetail:描述任务的元信息(谁来做、怎么做)。
- 关系:JobDetail 是 Job 的包装器,包含了 Job 的类信息和任务的额外信息。
- 设计目的:解耦任务逻辑和任务元信息,提高灵活性和可扩展性。
- 原理图:
- Job、JobDetail和Trigger的关系
Trigger:
- 一个 Trigger 只能绑定一个 JobDetail。
JobDetail:
- 一个 JobDetail 可以被多个 Trigger 绑定。相当于是一个Job信息可以被多次使用。
Job:
- 一个 Job 类可以创建多个 JobDetail 对象。相当于是可以允许多个JobDetail使用一个Job的execute逻辑。
- 默认情况下,Quartz 每次触发器触发时都会创建一个新的 Job 实例,再去执行execute方法。(这样可以线程安全)
例子:
package com.example;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.*;
import static org.quartz.JobBuilder.newJob;
public class SimpleTriggerMisfireExample {
public static void main(String[] args) throws SchedulerException {
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
JobDetail job = newJob(MyJob.class)
.withIdentity("myJob", "group1")
.storeDurably()
.build();
Trigger trigger1 = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
Trigger trigger2 = TriggerBuilder.newTrigger()
.withIdentity("trigger2", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
.build();
Set<Trigger> triggers = new HashSet<>();
triggers.add(trigger1);
triggers.add(trigger2);
Map<JobDetail, Set<? extends Trigger>> triggersAndJobs = new HashMap<>();
triggersAndJobs.put(job, triggers);
scheduler.scheduleJobs(triggersAndJobs, false);
System.out.println("调度器启动时间: " + new Date());
scheduler.start();
try {
Thread.sleep(60000); // 等待 60 秒
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.shutdown();
}
public static class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) {
Trigger trigger = context.getTrigger();
System.out.println("任务执行开始: " + new Date() +
", Trigger: " + trigger.getKey() +
", 触发时间: " + trigger.getPreviousFireTime());
try {
Thread.sleep(3000); // 模拟任务执行耗时 3 秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务执行结束: " + new Date());
}
}
}
执行结果:
D:\jdk1.8.0_172\bin\java.exe "-javaagent:D:\IDEA\IntelliJ IDEA 2021.3.2\lib\idea_rt.jar=55136:D:\IDEA\IntelliJ IDEA 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk1.8.0_172\jre\lib\charsets.jar;D:\jdk1.8.0_172\jre\lib\deploy.jar;D:\jdk1.8.0_172\jre\lib\ext\access-bridge-64.jar;D:\jdk1.8.0_172\jre\lib\ext\cldrdata.jar;D:\jdk1.8.0_172\jre\lib\ext\dnsns.jar;D:\jdk1.8.0_172\jre\lib\ext\jaccess.jar;D:\jdk1.8.0_172\jre\lib\ext\jfxrt.jar;D:\jdk1.8.0_172\jre\lib\ext\localedata.jar;D:\jdk1.8.0_172\jre\lib\ext\nashorn.jar;D:\jdk1.8.0_172\jre\lib\ext\sunec.jar;D:\jdk1.8.0_172\jre\lib\ext\sunjce_provider.jar;D:\jdk1.8.0_172\jre\lib\ext\sunmscapi.jar;D:\jdk1.8.0_172\jre\lib\ext\sunpkcs11.jar;D:\jdk1.8.0_172\jre\lib\ext\zipfs.jar;D:\jdk1.8.0_172\jre\lib\javaws.jar;D:\jdk1.8.0_172\jre\lib\jce.jar;D:\jdk1.8.0_172\jre\lib\jfr.jar;D:\jdk1.8.0_172\jre\lib\jfxswt.jar;D:\jdk1.8.0_172\jre\lib\jsse.jar;D:\jdk1.8.0_172\jre\lib\management-agent.jar;D:\jdk1.8.0_172\jre\lib\plugin.jar;D:\jdk1.8.0_172\jre\lib\resources.jar;D:\jdk1.8.0_172\jre\lib\rt.jar;E:\develop\spring\target\classes;C:\Users\Administrator\.m2\repository\org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar;C:\Users\Administrator\.m2\repository\com\mchange\c3p0\0.9.5.4\c3p0-0.9.5.4.jar;C:\Users\Administrator\.m2\repository\com\mchange\mchange-commons-java\0.2.15\mchange-commons-java-0.2.15.jar;C:\Users\Administrator\.m2\repository\com\zaxxer\HikariCP-java7\2.4.13\HikariCP-java7-2.4.13.jar;C:\Users\Administrator\.m2\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;C:\Users\Administrator\.m2\repository\org\slf4j\slf4j-simple\1.7.36\slf4j-simple-1.7.36.jar com.example.SimpleTriggerMisfireExample
[main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
[main] INFO org.quartz.simpl.SimpleThreadPool - Job execution threads will use class loader of thread: main
[main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
[main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.2 created.
[main] INFO org