Quartz 的执行流程分析

Quartz 的执行流程分析

一、QuartzSchedulerThread 的 run方法大致阐述

先说一下run方法的执行时机:

当 Quartzscheduler执行start方法 时,方法体中有一句

schedThread.togglePause(false); ,接着就会调用 QuartzSchedulerThread 下的 togglePause 方法,将 paused 置为 false ,在此之后, QuartzSchedulerThread 下的 run 方法开始真正运行

/**通知主处理循环在下一个可能的点暂停 */ void togglePause(boolean pause) { synchronized (sigLock) { paused = pause; if (paused) { signalSchedulingChange(0); } else { sigLock.notifyAll(); } } }复制代码 public void run() { int acquiresFailed = 0; // 这里就是判断调度器是否该停止,如果没有收到信号的话,这个调度器是一直处于循环之中的 while (!halted.get()) { try { // 这里是检查我们是否应该暂停 synchronized (sigLock) { // 我们在初始化的时候,paused 是置为 true的, // 因此在上文中,我们才说 // 当 Quartzscheduler 执行 start方法时调用togglePause, // 将 paused 置为false,run 方法才开始运行 // 也是因为此处的判断 while (paused && !halted.get()) { try { sigLock.wait(1000L); }catch (InterruptedException ignore) {} acquiresFailed = 0; } if (halted.get()) { break;} } // 如果从作业存储中读取一直失败(例如数据库关闭或重新启动) // 就会等待一段时间~ if (acquiresFailed > 1) { try { //这里就是计算延迟时间 long delay = computeDelayForRepeatedErrors(qsRsrcs.getJobStore(), acquiresFailed); Thread.sleep(delay); } catch (Exception ignore) {} } // 从线程池拿出空闲可利用的线程数量 // 这里多谈一嘴 blockForAvailableThreads()方法 // 它是一个阻塞式方法,直到至少有一个可用线程。 int availThreadCount = qsRsrcs.getThreadPool().blockForAvailableThreads(); if(availThreadCount > 0) { List triggers; long now = System.currentTimeMillis(); // 清除信号调度变更 clearSignaledSchedulingChange(); try { //如果可用线程数量足够那么就是30后再次扫描, //acquireNextTriggers方法的三个参数的意思分别是: //idleWaitTime :为如果没有的再次扫描的时间,默认是 // private static long DEFAULT_IDLE_WAIT_TIME = 30L * 1000L; 30秒 //Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()) :这里的意思就是一次最多能取几个出来 //batchTimeWindow :默认是0,同样是一个时间范围, //如果有两个任务只差一两秒,而执行线程数量满足及batchTimeWindow时间也满足的情况下就会两个都取出来 // 具体的方法的执行,后文再看~ triggers = qsRsrcs.getJobStore().acquireNextTriggers( now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow()); acquiresFailed = 0; if (log.isDebugEnabled()){ //… } //在获取到 triggers 触发器不为空后, //trigger列表是以下次执行时间排序查出来的 if (triggers != null && !triggers.isEmpty()) { now = System.currentTimeMillis(); //取出集合中最早执行的触发器 //获取它的下一个触发时间 long triggerTime = triggers.get(0).getNextFireTime().getTime(); long timeUntilTrigger = triggerTime – now; // 判断距离执行时间是否大于2 毫秒 while(timeUntilTrigger > 2) { synchronized (sigLock) { if (halted.get()) { break; } //判断是不是距离触发事件最近的, if (!isCandidateNewTimeEarlierWithinReason(triggerTime, false)) { try { // 没有的话,就进行阻塞,稍后进行执行 now = System.currentTimeMillis(); timeUntilTrigger = triggerTime – now; if(timeUntilTrigger >= 1) sigLock.wait(timeUntilTrigger); } catch (InterruptedException ignore) {} } } if(releaseIfScheduleChangedSignificantly(triggers, triggerTime)) { break; } now = System.currentTimeMillis(); timeUntilTrigger = triggerTime – now; } // this happens if releaseIfScheduleChangedSignificantly decided to release triggers if(triggers.isEmpty()) continue; // set triggers to ‘executing’ List bndles = new ArrayList(); boolean goAhead = true; synchronized(sigLock) { goAhead = !halted.get(); } if(goAhead) { try { //开始根据需要执行的trigger从数据库中获取相应的JobDetail 同时这一步也更新了 triggers 的状态,稍后会讲到~ List res = qsRsrcs.getJobStore().triggersFired(triggers); if(res != null) bndles = res; } catch (SchedulerException se) { qs.notifySchedulerListenersError( “An error occurred while firing triggers ‘” + triggers + “‘”, se); for (int i = 0; i < triggers.size(); i++) { qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i)); } continue; } } //将查询到的结果封装成为 TriggerFiredResult for (int i = 0; i 0) // should never happen, if threadPool.blockForAvailableThreads() follows contract continue; // while (!halted) } long now = System.currentTimeMillis(); long waitTime = now + getRandomizedIdleWaitTime(); long timeUntilContinue = waitTime – now; synchronized(sigLock) { // …. } } // …. } // while (!halted) // …. }复制代码

二、一些细节

2.1、先获取线程池中的可用线程数量

(若没有可用的会阻塞,直到有可用的);

int availThreadCount = qsRsrcs.getThreadPool().blockForAvailableThreads(); 复制代码

2.2、获取 30m 内要执行的 trigger

(即 acquireNextTriggers )

我们来看一看 acquireNextTriggers 方法

首先说 acquireNextTriggers 具体实现是在 JobStoreSupport 中,同时 quartz 与数据库关联的实现大都在 JobStoreSupport 中,当然更具体的SQL执行还是在 DriverDelegate 接口下的。

acquireNextTriggers 做了哪些事情呢?

我们看看这两个方法:

首先看第一个 acquireNextTrigger(conn, noLaterThan, maxCount, timeWindow);

主要就是获取下一个 30m内可执行的triggers的触发器,在里面 JobStoreSupport 从数据库取出 triggers 时是按照 nextFireTime 排序的

更具体的就需要大家点进方法去看啦~另外里面还包含triggers状态的变更,属于是更加细节化的东西。

第二个就是获取到触发的触发记录~

然后在执行 executeInNonManagedTXLock 时,是需要先获得锁,之后再在提交时释放锁的。

待直到获取的trigger中最先执行的trigger在2ms内;

if (triggers != null && !triggers.isEmpty()) { now = System.currentTimeMillis(); long triggerTime = triggers.get(0).getNextFireTime().getTime(); long timeUntilTrigger = triggerTime – now; while(timeUntilTrigger > 2) { //… } }复制代码

2.3、triggersFired(triggers)

List res = qsRsrcs.getJobStore().triggersFired(triggers);

这一步看着只是获取了 List 对象,实际上在 triggersFired(triggers) 方法中隐藏了很多东西~

首先查询,确保触发器没有被删除、暂停或完成…,就更新 firedTrigger 的 status=STATE_EXECUTING ;代码的注释上还说,如果没有这些就会将状态该为 deleted

另外就是更新触发触发器:

  • 更新trigger下一次触发的时间;
  • 更新trigger的状态:
  • 如果下一次的执行时间为空,状态则改为 STATE_COMPLETE

    在执行 executeInNonManagedTXLock 方法时,提交前先获得锁, transOwner = getLockHandler().obtainLock(conn, lockName);

    最后是释放锁: commitConnection(conn);

    2.4、创建JobRunShell,放进线程池执行

    针对每个要执行的trigger,创建JobRunShell,并放入线程池执行:

    然后由execute:执行job

    更详细的看不下去啦~

    来源:https://juejin.cn/post/7131671438901116935

    郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
    用户投稿
    上一篇 2022年8月16日 09:34
    下一篇 2022年8月16日 09:34

    相关推荐

    • 分享4条发微商朋友圈的方法(微商朋友圈应该怎么发)

      对于微商朋友来说,朋友圈的重要性不言而喻了。 那么微商的朋友圈到底该怎么发呢? 为什么同样是经营一个朋友圈,有的微商看起来逼格满满,实际效果也不错;而有的却动都不动就被屏蔽甚至拉黑…

      2022年11月27日
    • 《宝可梦朱紫》梦特性怎么获得?隐藏特性获取方法推荐

      宝可梦朱紫里有很多宝可梦都是拥有梦特性会变强的宝可梦,很多玩家不知道梦特性怎么获得,下面就给大家带来宝可梦朱紫隐藏特性获取方法推荐,感兴趣的小伙伴一起来看看吧,希望能帮助到大家。 …

      2022年11月25日
    • 《宝可梦朱紫》奇鲁莉安怎么进化?奇鲁莉安进化方法分享

      宝可梦朱紫中的奇鲁莉安要怎么进化呢?很多玩家都不知道,下面就给大家带来宝可梦朱紫奇鲁莉安进化方法分享,感兴趣的小伙伴一起来看看吧,希望能帮助到大家。 奇鲁莉安进化方法分享 奇鲁莉安…

      2022年11月25日
    • 5+3疫情防控从哪天开始算(辽宁疫情防控最新政策)

      最近有关国内各地的疫情大家也都有在持续关注,目前国内各地疫情隔离时间也根据二十条防控措施有了新的调整。那么,5+3疫情防控从哪天开始算?对于密接的5+3隔离时间计算大家还是比较关心…

      2022年11月25日
    • 蓝码怎么变绿码需要几天(蓝码怎么变绿码需要几天)

      大家都知道健康码的颜色有红码、绿码、黄码,近日湖南健康码上线“蓝码”,不少小伙伴发现自己健康码变蓝了,都想赶紧恢复绿码,那么蓝码怎么变绿码需要几天?下面小编为大家带来蓝码变绿码需要…

      2022年11月25日
    • 拼多多百亿补贴预售一般多久发货(拼多多百亿补贴预售)

      拼多多里面有很多优惠活动,其中百亿补贴活动非常火爆,一些里面的东西价格比别的平台便宜,质量也有保障,还有预售的活动,那么拼多多百亿补贴预售一般多久发货?下面小编为大家带来拼多多百亿…

      2022年11月25日
    • 北京疫情多久能解除封控(北京疫情还要多久结束)

      最近一段时间北京疫情形势备受关注,马上就要到年底了,不少人想要去北京办事,。都非常关注当地疫情相关政策,那么 北京疫情多久能解除封控?北京疫情什么时候恢复正常生活?下面小编为大家带…

      2022年11月25日
    • 客服的岗位职责怎么写(客服工作内容及职责)

      各位小伙伴们大家周一好,又到了每周一给大家分享干货内容的时候啦~ 本期来跟大家分享一下客服工作管理流程以及客服岗位里面的每项职能岗位的核心细则,也是干货满满推荐收藏~ 一.补偿流程…

      2022年11月25日
    • cpu性能天梯图2022 AMD CPU天梯图最新排行榜出炉

      用户在DIY自己的主机时选择CPU是非常关键的,CPU可以说是电脑的大脑,大家也都想追求好一点的CPU来使用,但型号太多了,大部分的用户都不知道目前哪一款CPU比较好用,快来看看详…

      2022年11月24日
    • 《宝可梦朱紫》暴飞龙怎么抓?暴飞龙获得方法

      宝可梦朱紫暴飞龙位置在哪?在游戏中,很多玩家还不清楚暴飞龙具体要怎么样获得,其实获得方法很简单,暴飞龙直接是没得抓的,需要玩家从宝贝龙进化得到,下面一起来看一下宝可梦朱紫暴飞龙获得…

      2022年11月23日

    联系我们

    联系邮箱:admin#wlmqw.com
    工作时间:周一至周五,10:30-18:30,节假日休息