中科时代建设官方网站,h5制作平台排行榜,sql数据库查询网站模板,爱站之家 我们在前面文章中说到过Quartz涉及到的线程#xff0c;但是散落在几篇文章中#xff0c;不好找。而Quartz涉及到的线程对于理解Quartz也比较重要#xff0c;所以今天专门提取出来单独说一下。
Quartz中的主要线程#xff1a; 任务调度线程QuartzSchedulerThread 任务执… 我们在前面文章中说到过Quartz涉及到的线程但是散落在几篇文章中不好找。而Quartz涉及到的线程对于理解Quartz也比较重要所以今天专门提取出来单独说一下。
Quartz中的主要线程 任务调度线程QuartzSchedulerThread 任务执行线程 Misfire处理线程 ClusterManager线程
任务调度线程 QuartzSchedulerThread
QuartzSchedulerThread是任务调度线程他的职责是对满足触发条件nextFireTimer到了的注册到JobStore的Trigger分配给可用的任务执行线程去执行。
QuartzSchedulerThread启动
任务调度线程QuartzSchedulerThread是在调度器Scheduler创建的时候启动的。
应用层通过以下调用创建Scheduler Scheduler sche new StdSchedulerFactory().getScheduler();
一般情况下通过StdSchedulerFactory构建SchedulergetScheduler首先尝试从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方法我们也大概分析过其主要逻辑是 从作业执行线程池获取availThreadCount也就是当前可用的线程数 调用JobStore的acquireNextTriggers方法获取特定短时间idleWaitTime默认30秒内可能需要被触发的数量不超过availThreadCount的触发器 调用JobStore的triggersFired方法对获取到的可能需要被触发的触发器进行二次加工再次获取到最终的待触发器结果集 循环处理最终的待处理触发器结果集中的每一个需要被触发的触发器 用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详细内容请参考Quartz - 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方法的主要逻辑为 从数据库中获取在WAITING等待执行状态、下次执行时间小于msifiredtime(当前时间 - MisfireThreshold)的触发器也就是错过触发时间的触发器 为了避免存在大量misfired trigger的情况下一次处理太多数据影响其他正常触发器的执行MisfireHandle线程每次仅获取部分而不是全部misfired trigger参数maxToRecoverAtATime指定默认为20 对获取到的每一个错过执行时间的触发器misfired trigger,调用触发器的updateAfterMisfire方法获取下次执行时间updateAfterMisfire方法我们在上一篇讲Misfire处理策略的文章中说过就是根据触发器的处理策略获取下次执行时间 updateAfterMisfire方法执行后获取到的触发器的下次执行时间如果不为空的话更新到数据库中等待正常的任务执行线程调度执行
ClusterManager线程
与MisfiredHandle一样ClusterManager线程也是JDBC-Based JobStore特有的。
顾名思义ClusterManager线程与集群有关系JDBC-Based JobStore是可以支持Quartz的集群部署的在集群环境下Quartz服务节点可能会down机、掉线从而影响任务的执行ClusterManager线程就是负责检查Quartz服务节点的在线状态的如果发生掉线后将该服务节点负责的触发器交给其他服务节点来处理。
具体逻辑等到我们分析完Quartz Cluster之后补充。