咱们在后面文章中说到过Quartz波及到的线程,然而散落在几篇文章中,不好找。而Quartz波及到的线程对于了解Quartz也比拟重要,所以明天专门提取进去独自说一下。

Quartz中的次要线程:

  1. 任务调度线程QuartzSchedulerThread
  2. 工作执行线程
  3. Misfire解决线程
  4. ClusterManager线程

任务调度线程 QuartzSchedulerThread

QuartzSchedulerThread是任务调度线程,他的职责是对满足触发条件(nextFireTimer到了)的注册到JobStore的Trigger调配给可用的工作执行线程去执行。

QuartzSchedulerThread启动

任务调度线程QuartzSchedulerThread是在调度器Scheduler创立的时候启动的。

应用层通过以下调用创立Scheduler:

Scheduler sche = new StdSchedulerFactory().getScheduler();

个别状况下通过StdSchedulerFactory构建Scheduler,getScheduler首先尝试从SchedulerRepository获取Schedule,首次运行获取不到,则通过instantiate()办法获取。

public Scheduler getScheduler() throws SchedulerException {        if (cfg == null) {            initialize();        }        SchedulerRepository schedRep = SchedulerRepository.getInstance();        Scheduler sched = schedRep.lookup(getSchedulerName());        if (sched != null) {            if (sched.isShutdown()) {                schedRep.remove(getSchedulerName());            } else {                return sched;            }        }        sched = instantiate();        return sched;    }

instantiate()办法特地特地特地长,简直就是在这里实现Quartz所有相干组件的初始化的。

其中会创立QuartzScheduler,之后会将QuartzScheduler包装到stdScheduler中存入SchedulerRepository。

instantiate()创立QuartzScheduler是调用的构造方法:

public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval)        throws SchedulerException {        this.resources = resources;        if (resources.getJobStore() instanceof JobListener) {            addInternalJobListener((JobListener)resources.getJobStore());        }        this.schedThread = new QuartzSchedulerThread(this, resources);        ThreadExecutor schedThreadExecutor = resources.getThreadExecutor();        schedThreadExecutor.execute(this.schedThread);        if (idleWaitTime > 0) {            this.schedThread.setIdleWaitTime(idleWaitTime);        }        jobMgr = new ExecutingJobsManager();        addInternalJobListener(jobMgr);        errLogger = new ErrorLogger();        addInternalSchedulerListener(errLogger);        signaler = new SchedulerSignalerImpl(this, this.schedThread);                getLog().info("Quartz Scheduler v." + getVersion() + " created.");    }

能够看到构造方法中创立了QuartzSchedulerThread对象,之后获取ThreadExecutor(个别状况下为DefaultThreadExecutor)并通过调用其execute办法启动QuartzSchedulerThread线程:

public class DefaultThreadExecutor implements ThreadExecutor {    public void initialize() {    }    public void execute(Thread thread) {        thread.start();    }}
QuartzSchedulerThread的运行

其实就是他的run办法,咱们也大略剖析过,其次要逻辑是:

  1. 从作业执行线程池获取availThreadCount,也就是以后可用的线程数
  2. 调用JobStore的acquireNextTriggers办法,获取特定短时间(idleWaitTime,默认30秒)内可能须要被触发的,数量不超过availThreadCount的触发器
  3. 调用JobStore的triggersFired办法对获取到的可能须要被触发的触发器进行二次加工,再次获取到最终的待触发器后果集
  4. 循环解决最终的待处理触发器后果集中的每一个须要被触发的触发器
  5. 用JobRunShell包装该触发器,送给线程池执行该触发器关联的作业

好了,作业调度线程QuartzSchedulerThread咱们就根本搞清楚了。

作业执行线程

Quartz的作业执行线程是放在线程池中进行治理的,默认是SimpleTreadPool,无关SimpleThreadPool咱们后面专门有一篇文章介绍过,这里就不再赘述了。

作业执行线程和作业调度线程一样,也是在作业调度器Scheduler创立后立刻启动,这个过程同样也是在StdSchedulerFactory的instantiate()办法中实现的:

instantiate()创立SimpleThreadPool之后会调用SimpleThreadPool的initialize办法,依据配置文件指定的工作执行线程数实现工作线程的初始化和启动。比方配置未见设置为10则初始化10个工作线程并一一启动。作业执行线程的初始化及启动的具体过程请参考Quartz - SimpleThreadPool。

MisfireHandler线程

如果你的我的项目应用RAMJobStore,而不是JDBC-based JobStore(指须要长久化到数据库的JobStore),那么就不存在Misfire解决线程。

因为RAMJobStore在解决失常触发的过程中顺便就解决了Misfire,所以就不再须要其余解决机制了,这部分咱们在后面的文章中也剖析过Quartz - Misfire (for RAMJobstore)。

JDBC-based JobStore在解决失常触发的时候只获取未错过触发工夫的触发器,对于错过触发工夫的、也就是Misfire的触发器就须要另外的机制来解决。

Misfire解决线程就是Quartz采纳JDBC-based JobStore的状况下用来解决错过触发机会的触发器的线程。

MisfireHandler启动

MisfireHandler定义在JobStoreSupport类中,JobStoreSupport是JobStore的JDBC-based JobStore的虚构类,Quartz次要提供了两个基于JDBC的JobStore的实现:JobStoreTX、JobStoreCMT。JDBC-based JobStore咱们当前剖析,明天次要剖析MisfireHandler。

咱们在利用中创立任务调度器Scheduler后须要调用他的start办法:

 Scheduler sche = new StdSchedulerFactory().getScheduler();            sche.scheduleJob(jobDetail,trigger);            sche.start();

这个start办法会调用到JobStore的schedulerStarted()办法,如果咱们利用中采纳的是JDBC-based JobStore的话,会调用到JobStoreSupport的schedulerStarted(),其中会创立MisfireHandler之后调用MisfireHandler的initialize():

misfireHandler = new MisfireHandler();        if(initializersLoader != null)            misfireHandler.setContextClassLoader(initializersLoader);        misfireHandler.initialize();

Misfire的initialize将创立好的MisFireHandle线程交给ThreadExecutor启动。

public void initialize() {            ThreadExecutor executor = getThreadExecutor();            executor.execute(MisfireHandler.this);        }
MisfireHandle的运行

也就是MisfireHandle的run办法。解决逻辑和RAMJobStore解决misfired trigger的逻辑相似,只不过MisfireHandle的所有解决逻辑都是通过数据库操作实现的。

JDBC-Based JobStore对应的表构造咱们会找机会专门剖析,这里就不具体开展了。

MisfireHandle的run办法的次要逻辑为:

  1. 从数据库中获取在WAITING(期待执行)状态、下次执行工夫小于msifiredtime(以后工夫 - MisfireThreshold)的触发器,也就是错过触发工夫的触发器
  2. 为了防止存在大量misfired trigger的状况下,一次解决太多数据影响其余失常触发器的执行,MisfireHandle线程每次仅获取局部而不是全副misfired trigger(参数maxToRecoverAtATime指定,默认为20)
  3. 对获取到的每一个错过执行工夫的触发器(misfired trigger),调用触发器的updateAfterMisfire办法获取下次执行工夫,updateAfterMisfire办法咱们在上一篇讲Misfire解决策略的文章中说过,就是依据触发器的解决策略获取下次执行工夫
  4. updateAfterMisfire办法执行后,获取到的触发器的下次执行工夫如果不为空的话,更新到数据库中,期待失常的工作执行线程调度执行

ClusterManager线程

与MisfiredHandle一样,ClusterManager线程也是JDBC-Based JobStore特有的。

顾名思义,ClusterManager线程与集群有关系,JDBC-Based JobStore是能够反对Quartz的集群部署的,在集群环境下,Quartz服务节点可能会down机、掉线,从而影响工作的执行,ClusterManager线程就是负责查看Quartz服务节点的在线状态的,如果产生掉线后,将该服务节点负责的触发器交给其余服务节点来解决。

具体逻辑等到咱们剖析完Quartz Cluster之后补充。

上一篇 easypoi 模板导出foreach单行多后果集+合并单元格问题