quartz核心元素及底层原理介绍
Quartz的核心元素主要有Scheduler、Trigger、Job、JobDetail。其中
- Scheduler为调度器负责整个定时系统的调度,内部通过线程池进行调度,下文阐述。
- Trigger为触发器记录着调度任务的时间规则,主要有四种类型:SimpleTrigger、CronTrigger、DataIntervalTrigger、NthIncludedTrigger,在项目中常用的为:SimpleTrigger和CronTrigger。
- JobDetail为定时任务的信息载体,可以记录Job的名字、组及任务执行的具体类和任务执行所需要的参数
- Job为任务的真正执行体,承载着具体的业务逻辑。
元素之间的关系如下:
介绍:先由SchedulerFactory创建Scheduler调度器后,由调度器去调取即将执行的Trigger,执行时获取到对于的JobDetail信息,找到对应的Job类执行业务逻辑。
quartz中线程主要分为执行线程和调度线程。
- 执行线程主要由一个线程池维护,在需要执行定时的时候使用
- 调度线程主要分为regular Scheduler Thread和Misfire Scheduler Thread;其中Regular Thread 轮询Trigger,如果有将要触发的Trigger,则从任务线程池中获取一个空闲线程,然后执行与改Trigger关联的job;Misfire Thraed则是扫描所有的trigger,查看是否有错失的,如果有的话,根据一定的策略进行处理。
quartz启动流程
当服务器启动时,Spring就加载相关的bean。SchedulerFactoryBean实现了InitializingBean接口,因此在初始化bean的时候,会执行afterPropertiesSet方法,该方法将会调用SchedulerFactory(DirectSchedulerFactory 或者 StdSchedulerFactory,通常用StdSchedulerFactory)创建Scheduler。我们在SchedulerFactoryBean配置类中配了相关的配置及配置文件参数,所以会读取配置文件参数,初始化各个组件。关键组件如下:
- ThreadPool:既上面所说的执行线程,一般是使用SimpleThreadPool(线程数量固定的线程池),SimpleThreadPool创建了一定数量的WorkerThread实例来使得Job能够在线程中进行处理。WorkerThread是定义在SimpleThreadPool类中的内部类,它实质上就是一个线程。在SimpleThreadPool中有三个list:workers-存放池中所有的线程引用,availWorkers-存放所有空闲的线程,busyWorkers-存放所有工作中的线程;配置如下
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=3
org.quartz.threadPool.threadPriority=5
- JobStore初始化定时任务的数据存储方式,分为两种:存储在内存的RAMJobStore和存储在数据库的JobStoreSupport(包括JobStoreTX和JobStoreCMT两种实现,JobStoreCMT是依赖于容器来进行事务的管理,而JobStoreTX是自己管理事务),若要使用集群要使用JobStoreSupport的方式;
- QuartzSchedulerThread初始化调度线程,在初始化的时候paused=true,halted=false,虽然线程开始运行了,但是paused=true,线程会一直等待,直到start方法将paused置为false;SchedulerFactoryBean还实现了SmartLifeCycle接口,因此初始化完成后,会执行start()方法,该方法将主要会执行以下的几个动作:
- 创建ClusterManager线程并启动线程:该线程用来进行集群故障检测和处理
- 创建MisfireHandler线程并启动线程:该线程用来进行misfire任务的处理
- 置QuartzSchedulerThread的paused=false,调度线程才真正开始调度
整个启动流程图如下:
流程图简要说明:
- 先读取配置文件
- 初始化SchedulerFactoryBean
- 初始化SchedulerFactory
- 实例化执行线程池(TheadPool)
- 实例化数据存储
- 初始化QuartzScheduler(为Scheduler的简单实现,包括调度作业、注册JobListener实例等方法。)
- new一个QuartzSchedulerThread调度线程(负责执行在QuartzScheduler中注册的触发触发器的线程。),并开始运行
- 调度开始,注册监听器,注册Job和Trigger
- SchedulerFactoryBean初始化完成后执行start()方法
- 创建ClusterManager线程并启动线程
- 创建MisfireHandler线程并启动线程
- 置QuartzSchedulerThread的paused=false,调度线程真正开始调度,开始执行run方法
QuartzSchedulerThread逻辑具体介绍:
类中主要的方法就是run方法,下面主要对run方法进行介绍:
//只有当Quartzscheduler执行start方法时被调用
void togglePause(boolean pause) {
synchronized(this.sigLock) {
this.paused = pause;
if (this.paused) {
this.signalSchedulingChange(0L);
} else {
this.sigLock.notifyAll();
}
}
}
public void run() {
boolean lastAcquireFailed = false;
label214:
//此处判断调度器是否终止
while(!this.halted.get()) {
try {
synchronized(this.sigLock) {
//此处判断调度器是否终止或是否暂停,由于我们在初始化的时候
//将paused=true,那么调度线程此时不会真正开始执行只会在不断循环阻塞