Quartz-SchedulerThread调度逻辑

转载请注明出处:https://www.cnblogs.com/Dorae/p/9357180.html

本文出自:后端知识点梳理-定时任务Quartz篇章

先看一遍整理过的时序图,有个基本印象:

Quartz-SchedulerThread调度逻辑_第1张图片

 

QuartzSchedulerThread线程是实际执行任务调度的线程,其中主要代码如下。

public class QuartzSchedulerThread extends Thread {
    private QuartzScheduler qs;
    private QuartzSchedulerResources qsRsrcs;
    private final Object sigLock;
    private boolean signaled;
    private long signaledNextFireTime;
    private boolean paused;
    private AtomicBoolean halted;
    private Random random;
    private static long DEFAULT_IDLE_WAIT_TIME = 30000L;
    private long idleWaitTime;
    private int idleWaitVariablness;
    private final Logger log;
    private static final long MIN_DELAY = 20L;
    private static final long MAX_DELAY = 600000L;

while (!halted.get()) {
    //...省略
    //第一步,获取可用线程数量(阻塞)
	int availThreadCount = qsRsrcs.getThreadPool().blockForAvailableThreads();

    //第二步,获取30分钟内执行的Trigger
	triggers = qsRsrcs.getJobStore().acquireNextTriggers(now + idleWaitTime,
			Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow());
	long triggerTime = triggers.get(0).getNextFireTime().getTime();
	long timeUntilTrigger = triggerTime - now;

    //第三步,等待直到最先执行的Trigger在2分钟内
	while (timeUntilTrigger > 2) {
		now = System.currentTimeMillis();
		timeUntilTrigger = triggerTime - now;
	}

    //第四步,triggersFired
	List bndle = qsRsrcs.getJobStore().triggersFired(triggers);

    //第五步,针对每个要执行的trigger,创建JobRunShell,并放入线程池执行
	for (int i = 0; i < res.size(); i++) {
		JobRunShell shell = qsRsrcs.getJobRunShellFactory().createJobRunShell(bndle);
		shell.initialize(qs);
		qsRsrcs.getThreadPool().runInThread(shell);
	}
}
    //...省略

}

1:先获取线程池中的可用数量(若没有可用的会阻塞,直到有可用的);

2:获取30m内要执行的trigger(即acquireNextTriggers):

获取trigger的锁,通过select …for update方式实现;获取30m内(可配置)要执行的triggers(需要保证集群节点的时间一致),若@ConcurrentExectionDisallowed且列表存在该条trigger则跳过,否则更新trigger状态为ACQUIRED(刚开始为WAITING);插入firedTrigger表,状态为ACQUIRED;(注意:在RAMJobStore中,有个timeTriggers,排序方式是按触发时间nextFireTime排的;JobStoreSupport从数据库取出triggers时是按照nextFireTime排序);

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

4:triggerFired

  1. 更新firedTrigger的status=EXECUTING;

  2. 更新trigger下一次触发的时间;

  3. 更新trigger的状态:无状态的trigger->WAITING,有状态的trigger->BLOCKED,若nextFireTime==null ->COMPLETE;

  4. commit connection,释放锁;

 

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

  1. execute:执行job

  2. 获取TRIGGER_ACCESS锁

  3. 若是有状态的job:更新trigger状态:BLOCKED->WAITING,PAUSED_BLOCKED->BLOCKED

  4. 若@PersistJobDataAfterExecution,则updateJobData

  5. 删除firedTrigger

  6. commit connection,释放锁

调度过程中Trigger状态变化如下图:

Quartz-SchedulerThread调度逻辑_第2张图片

 

 

 

你可能感兴趣的:(Quartz-SchedulerThread调度逻辑)