SchedulerFactory & Scheduler & QuartzScheduler & QuartzSchedulerThread & ThreadExecutor(DefaultThreadExecutor) & ThreadPool(SimpleThreadPool and WorkThread)是Quartz调度任务的核心类,
Scheduler
SchedulerFactory负责收集配置信息,然后初始化Scheduler需要的资料,然后创建一个Scheduler对象
Scheduler的信息存储在QRTZ_scheduler_state表中;
scheduler的check;
SchedulerContext的配置方法
org.quartz.context.key.SOME_KEY=SOME_VALUE
SchedulerContext有什么用?Quartz默认一般都用来存储什么信息?
Scheduler实例持有一个QuartzSchedulerThread对象,Scheduler中负责启动此线程。
QuartzSchedulerThread是大老板,获取Trigger及Trigger关联的Job和其他相关信息,包装成JobRunShell,调用SimpleThreadPool#runInThread传递给包工头SimpleThreadPool,SimpleThreadPool包工头下面有很多干活的工人WorkThread,这些干活的工人最大的特点就是干完一个任务可以接着干另一个任务,WorkThread对象可以复用;SimpleThreadPool有个小本本,记录着哪些工人忙着,哪些工人闲着,availWorkers,busyWorkers字段;如果来了一个任务,没有空闲的工人,就需要等着。
QuartzSchedulerThread
org.quartz.scheduler为前缀的配置中,有相当一部分是给QuartzSchedulerThread配置的;
org.quartz.scheduler.threadName:Scheduler持有的QuartzSchedulerThread的线程的名称,默认是Scheduler_Name+“_QuartzSchedulerThread”
org.quartz.scheduler.makeSchedulerThreadDaemon:Scheduler持有的QuartzSchedulerThread的线程的名称是否设置成Deamon
org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer:是否集成初始化器的ClassLoader,在StdSchedulerFactory中初始化QuartScheduler对象,在QuartScheduler中初始化QuartzSchedulerThread,在QuartzSchedulerThread中设置本线程执行时使用的ContextClassLoader,也就是说如果设置成true,跟Scheduler在一个ContextClassLoader
org.quartz.scheduler.idleWaitTime:这个配置最终是给QuartzScheudlerThread使用的,QuartzScheudlerThread的run方法里会用到此参数的值,run方法的while循环再处理完Triggers之后,会使用此值计算一个等待时间,让线程等待一段时间啥也不做,也就是让线程空闲一段时间;
org.quartz.scheduler.batchTriggerAcquisitionMaxCount:这个配置最终是给QuartzScheudlerThread使用的,用来jobStore#acquireNextTriggers的时候使用,用来一次性获取的最大的Trigger数;
org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow:从Trigger表里查询将要fire的Triggers的时候,不能等到now=next_fire_time的时候再触发,程序本身还有运行的时间,这个时候需要指定一个提前的时间窗口。
已jdbcjobstore为例:
查询next fire triggers的时候,需要org.quartz.jobStore.misfireThreshold/org.quartz.scheduler.idleWaitTime/org.quartz.scheduler.batchTriggerAcquisitionMaxCount/org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow
最终生成的查询语句的条件是
now-threshold<=next_fire_time<=now+idlewaittime+timewinodw
now-threshold<=next_fire_time的意思是查询还没有misfire的Trigger
如果next_fire_time>now+idlewaittime+timewinod,也就是说放到下次查询触发这些tiggers,也晚不了;也就是说next_fire_time<=now+idlewaittime+timewinodw查询的是,不能放到下次查询触发,不然就晚了的Triggers。
org.quartz.scheduler.dbFailureRetryInterval:QuartzSchedulerThread从JobStore获取Triggers的时候,可能会因为JobStore持有的Connection比如JdbcConnection失效,QuartzSchedulerThread的run方法内是个whhile循环,在下一次循环尝试获取的时候,需要使用Thread.sleep让QuartzSchedulerThread睡一会,这个一会就是根据此配置的值计算出来的。
org.quartz.scheduler.classLoadHelper.class:scheuler运行过程中实例化类什么的用的ClassLoader
org.quartz.scheduler.jobFactory.class:在生成jobDetails对象的时候,我们指定的是一个类名,也就是说这个类需要实例化,然后执行实例化后的对象的execute方法,jobFactory就是用来实例化job的。这个地方可以扩展的原因是,生成job之后,我们可以做很多的工作,比如SpringBeanJobFactory增加了给Job对象注入Spring IOC容器内的Bean的能力;Quartz内置的PropertSeetingJobFactory可以将JobDataMap里的信息注入到Job对象的set方法;
ThreadExecutor
ThreadExecutor,线程执行器,提供了两种实现
DefaultThreadExecutor和WorkManagerThreadExecutor
DefaultThreadExecutor直接调用thread.start()启动线程
WorkManagerThreadExecutor是试用commonj执行线程
ThreadExecutor一个Scheduler持有一个,在ScheduleFactory中被初始化之后,在三个地方使用到了,ClusterManager MifireHandler 和在QuartzScheduler中启用QuartzSchedulerThread线程,这三个线程是quartz的三个主线程,所有的活都是这三个线程干的。
org.quartz.threadExecutor.class
ThreadPool
ThreadPool是用来执行用户提交的Job的,一个Scheduler对象一个;
QuartzScheulerThread的作用是从JobStore取出Trigger执行关联的job,使用JobRunShell这个Java Runnable的实现包裹关联的Job,然后将Job放到ThreadPool中执行;
SimpleThreadPool实现解析,
org.quartz.threadPool.class
org.quartz.threadPool.threadCount
org.quartz.threadPool.threadPriority
SimpleThreadPool
org.quartz.threadPool.makeThreadsDaemons
org.quartz.threadPool.threadsInheritGroupOfInitializingThread
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread
org.quartz.threadPool.threadNamePrefix
注解
- DisallowConcurrentExecution
- ExecutionInJTATranaction
- PersistJobDataAfterExecution:QRTZ_JOB_DETAILS表中的Job_DATA字段,如果在Job类上添加了PersistJobDataAfterExecution注解,会序列化到此字段;是Java 序列化
参考
如何让一个Quartz实例不执行任务:此博客展示了一个ThreadExecutor的高级用法,通过自定义一个ThreadExecutor,达到不启用这三个线程的目的;