Quartz源码阅读
Quartz—学习01—Quartz入门
Quartz—学习02—Quartz源码阅读
一、Quartz的整套流程
1-1、初始化过程
我以Quartz—学习01—Quartz入门的quartz-learn-001的demo为列进行源码阅读。
在Test类中有scheduler =schedulerFactory.getScheduler(); 这样一段代码,用于从SchedulerFactory工厂中获取Scheduler对象。下面以StdSchedulerFactory类中的getScheduler() 方法为例看一下其是怎么创建Scheduler 对象的。
// ########################## StdSchedulerFactory类 ######################
public Scheduler getScheduler() throws SchedulerException {
if (cfg == null) {
initialize(); // 初始加载配置文件,默认加载quartz.properties
//如果没有quartz.properties然后去加载/quartz.properties;
//如果都没有的话,会加载自带的org/quartz/quartz.properties文件
}
// 初始化一个SchedulerRepository;SchedulerRepository中有一个Map,这个Map用于存放Scheduler,key为Scheduler的Name,value为Scheduler对象
SchedulerRepository schedRep = SchedulerRepository.getInstance();
// 从SchedulerRepository
Scheduler sched = schedRep.lookup(getSchedulerName());
if (sched != null) {
if (sched.isShutdown()) {
schedRep.remove(getSchedulerName());
} else {
return sched;
}
}
// 初始化一个Scheduler的实例,这个instantiate()方法代码很长,将在下面进行介绍。
sched = instantiate();
return sched;
}
加载自带的 org/quartz/quartz.properties 文件内容。
##############################
# scheduler的配置属性
##############################
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
# Scheduler通过RMI作为服务器导出本身。
org.quartz.scheduler.rmi.export: false
# 是否是连接远程服务的调用程序,如果“是”需要指定RMI注册表进程的主机和端口
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
##############################
# threadPool的配置属性 ##
##############################
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
##############################
# jobStore的配置属性 ##
##############################
# 触发超时时间
org.quartz.jobStore.misfireThreshold: 60000
# 默认使用RAMJobStore存,也就是把调度信息存储在内存中
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
下面是StbSchedulerFactory的instantiate() 方法代码片段,这个方法主要作用是实例化一个Scheduler对象并对其进行一系列初始化操作,这个方法的代码有几百行,就不把代码粘贴出来了,具体细节可以参考源码进行阅读,这里就粘贴几个重要的步骤的代码。
....
// 从配置文件中获取配置信息
// 01-线程池配置
// 02-JobStore配置
// 03-数据源配置
// 04-SchedulerPlugin设置
// 05-JobListener设置
// 06-TriggerListener设置
// 08-ThreadExecutor设置
// 09-QuartzSchedulerResources设置
// JobRunShellFactory初始化配置
jrsf.initialize(scheduler);
// tp为ThreadPool,initialize主要作用是创建WorkerThread,并启动线程;具体代码看:代码001
tp.initialize();
...
// 实例化QuartzScheduler,具体代码看:代码002
qs = new QuartzScheduler(rsrcs, idleWaitTime, dbFailureRetry);
代码001
ThreadPool【具体实现以SimpleThreadPool为例】的instantiate()方法,该方法主要作用是获取WorkerThread线程并启动线程。
################ SimpleThreadPool的instantiate()方法 ############
public void initialize() throws SchedulerConfigException {
// 已经初始化过了
if(workers != null && workers.size() > 0)
return;
// 线程数量必须大于0
if (count <= 0) {
throw new SchedulerConfigException("Thread count must be > 0");
}
// 线程优先级必须在大于0小于等于9
if (prio <= 0 || prio > 9) {
throw new SchedulerConfigException("Thread priority must be > 0 and <= 9");
}
// isThreadsInheritGroupOfInitializingThread默认返回ture
if(isThreadsInheritGroupOfInitializingThread()) {
// 获取该线程对应的线程组
threadGroup = Thread.currentThread().getThreadGroup();
} else {
// 按照threadGroup树到根线程组。
threadGroup = Thread.currentThread().getThreadGroup();
ThreadGroup parent = threadGroup;
while ( !parent.getName().equals("main") ) {
threadGroup = parent;
parent = threadGroup.getParent();
}
threadGroup = new ThreadGroup(parent, schedulerInstanceName + "-SimpleThreadPool");
if (isMakeThreadsDaemons()) {
threadGroup.setDaemon(true);
}
}
// 默认为false
if (isThreadsInheritContextClassLoaderOfInitializingThread()) {
getLog().info("Job execution threads will use class loader of thread: " + Thread.currentThread().getName());
}
// 创建WorkerThread,WorkerThread默认为权重为5,非守护线程。count为10,
Iterator<WorkerThread> workerThreads = createWorkerThreads(count).iterator();
while(workerThreads.hasNext()) {
WorkerThread wt = workerThreads.next();
// 启动线程,WorkerThread的run方法如下所示
wt.start();
// 把线程放到存放可用线程的Map中,初始化为10个
availWorkers.add(wt);
}
}
##################### WorkThread类 ################
@Override
public void run() {
boolean ran = false;
// run默认为ture,调用shutdown()方法后会修改为false,
// run.get():用于判断Quartz是否暂停了。如果线程启动
while (run.get()) {
try {
// 上锁操作,
synchronized(lock) {
// 判断是否有工作,或者工作是否暂停,如果是就没0.5检查一次
while (runnable == null && run.get()) {
lock.wait(500);
}
if (runnable != null) {
ran = true;
// 执行runnable的run方法
runnable.run();
}
}
} catch (InterruptedException unblock) {
try {
getLog().error("Worker thread was interrupt()'ed.", unblock);
} catch(Exception e) {
}
} catch (Throwable exceptionInRunnable) {
try {
getLog().error("Error while executing the Runnable: ", exceptionInRunnable);
} catch(Exception e) {
}
} finally {
synchronized(lock) {
runnable = null;
}
// 修复线程,【没看明白】
if(getPriority() != tp.getThreadPriority()) {
setPriority(tp.getThreadPriority());
}
// 是否只跑一次,默认为false,当有runnable的初始化的WorkThread的时候,会修改为ture
if (runOnce) {
run.set(false);
// 从busyWorkers中移除
clearFromBusyWorkersList(this);
} else if(ran) {
ran = false;
// availWorkers添加改线程,并从busyWorkers中移除
makeAvailable(this);
}
}
}
try {
getLog().debug("WorkerThread is shut down.");
} catch(Exception e) {
}
}
代码002
QuartzScheduler的构造函数QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval)。在QuartzScheduler初始化过程中主要做了:通过给定的QuartzSchedulerResources创建QuartzSchedulerThread实例,并启动QuartzSchedulerThread实例,并把对应的监听器加入到QuartzScheduler中。QuartzSchedulerThread的run方法主要做了:判断线程是否启动和Quartz是否启动,如果没有启动,就一直检查;如果启动以后,检查当前时候有可用的Trigger。
// #################### QuartzScheduler的构造函数。 ##############
public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval) throws SchedulerException {
// 把SchedulerFactory初始化的QuartzSchedulerResources赋给QuartzScheduler的QuartzSchedulerResources
this.resources = resources;
// 判断JobStore是否是JobListener的子类
if (resources.getJobStore() instanceof JobListener) {
addInternalJobListener((JobListener)resources.getJobStore());
}
// 实例一个QuartzSchedulerThread对象通过QuartzScheduler和QuartzSchedulerResources
this.schedThread = new QuartzSchedulerThread(this, resources);
// 获取QuartzSchedulerResources中的ThreadExecutor
ThreadExecutor schedThreadExecutor = resources.getThreadExecutor();
// 把QuartzSchedulerThread启动起来,下面是QuartzSchedulerThread的run方法。
schedThreadExecutor.execute(this.schedThread);
if (idleWaitTime > 0) {
this.schedThread.setIdleWaitTime(idleWaitTime);
}
// 添加JobListener监听
jobMgr = new ExecutingJobsManager();
addInternalJobListener(jobMgr);
// 添加schedulerListener监听
errLogger = new ErrorLogger();
addInternalSchedulerListener(errLogger);
signaler = new SchedulerSignalerImpl(this, this.schedThread);
if(shouldRunUpdateCheck())
updateTimer = scheduleUpdateCheck();
else
updateTimer = null;
getLog().info("Quartz Scheduler v." + getVersion() + " created.");
}
// #################### QuartzSchedulerThread ##################
@Override
public void run() {
boolean lastAcquireFailed = false;
// halted初始化为false,用于判断quartz是否是暂停状态,默认不是暂停状态;
// paused初始化默认为ture,用于判断是否暂停状态,默认为暂停状态。
while (!halted.get()) {
try {
// 初始化的时候Quartz不是暂停状态,但是是未启动状态。
// 没过1秒检查一次,Quartz是否启动并且不是暂停状态。如果QuartzScheduler的start()方法被调用以后paused会被置为ture.
// 只有启动的时候才会把paused设为false,所以初始化的时候一直在等待,直到启动为止。
synchronized (sigLock) {
while (paused && !halted.get()) {
try {
sigLock.wait(1000L);
} catch (InterruptedException ignore) {
}
}
if (halted.get()) {
break;
}
}
// 获取可用线程数。
int availThreadCount = qsRsrcs.getThreadPool().blockForAvailableThreads();
// 这个总是为ture
if(availThreadCount > 0) {
List<OperableTrigger> triggers = null;
long now = System.currentTimeMillis();
// 清除信号记录,把signaled设为ture
clearSignaledSchedulingChange();
try {
// acquireNextTriggers()方法获取到OperableTrigger的集合,并按执行时间的先后顺序放入list中。这个方法可以看一下源码
//(当前时间 + 30s, [availThreadCount,maxBatchSize初始化为1]中小的一个, batchTimeWindow默认为0)
triggers = qsRsrcs.getJobStore().acquireNextTriggers(now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow());
lastAcquireFailed = false;
if (log.isDebugEnabled())
log.debug("batch acquisition of " + (triggers == null ? 0 : triggers.size()) + " triggers");
} catch (JobPersistenceException jpe) {
if(!lastAcquireFailed) {
qs.notifySchedulerListenersError("An error occurred while scanning for the next triggers to fire.", jpe);
}
lastAcquireFailed = true;
continue;
} catch (RuntimeException e) {
if(!lastAcquireFailed) {
getLog().error("quartzSchedulerThreadLoop: RuntimeException " + e.getMessage(), e);
}
lastAcquireFailed = true;
continue;
}
// 如果triggers是否为空
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) {
// quartz是否是在暂停状态
if (halted.get()) {
break;
}
//QuartzSchedule是否被改变了,没有改变isCandidateNewTimeEarlierWithinReason返回false,
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;
}
// 再次检查triggers是否为空。
if(triggers.isEmpty()) {
continue;
}
List<TriggerFiredResult> bndles = new ArrayList<TriggerFiredResult>();
boolean goAhead = true;
// 判断是否暂停。
synchronized(sigLock) {
goAhead = !halted.get(); // 没有出现暂停情况goAhead都为ture
}
if(goAhead) {
// 从QuartzSchedulerResources中获取对应的TriggerFiredResult集合,并赋给bndles;
try {
List<TriggerFiredResult> 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;
}
}
for (int i = 0; i < bndles.size(); i++) {
TriggerFiredResult result = bndles.get(i);
// 获取TriggerFiredBundle从TriggerFiredResult中,
TriggerFiredBundle bndle = result.getTriggerFiredBundle();
Exception exception = result.getException();
if (exception instanceof RuntimeException) {
getLog().error("RuntimeException while firing trigger " + triggers.get(i), exception);
qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));
continue;
}
if (bndle == null) {
qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));
continue;
}
//#################################################
// 创建对应的JobRunShell,并初始化
//#################################################
JobRunShell shell = null;
try {
shell = qsRsrcs.getJobRunShellFactory().createJobRunShell(bndle);
shell.initialize(qs);
} catch (SchedulerException se) {
qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bndle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR);
continue;
}
//#################################################
// 获取对应的JobRunShell,具体代码请看:代码004
//#################################################
if (qsRsrcs.getThreadPool().runInThread(shell) == false) {
getLog().error("ThreadPool.runInThread() return false!");
qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bndle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR);
}
}
continue;
}
} else {
continue;
}
long now = System.currentTimeMillis();
long waitTime = now + getRandomizedIdleWaitTime();
long timeUntilContinue = waitTime - now;
synchronized(sigLock) {
try {
if(!halted.get()) {
if (!isScheduleChanged()) {
sigLock.wait(timeUntilContinue);
}
}
} catch (InterruptedException ignore) {
}
}
} catch(RuntimeException re) {
getLog().error("Runtime error occurred in main trigger firing loop.", re);
}
}
qs = null;
qsRsrcs = null;
}
代码004
SimpleThreadPool的
//#################### SimpleThreadPool类 ########################
// 以runnable为JobRunShell实例为例
public boolean runInThread(Runnable runnable) {
if (runnable == null) {
return false;
}
synchronized (nextRunnableLock) {
handoffPending = true;
// 等待工作线程可用。
while ((availWorkers.size() < 1) && !isShutdown) {
try {
nextRunnableLock.wait(500);
} catch (InterruptedException ignore) {
}
}
// 判断Quartz是否停止了。
if (!isShutdown) {
// 从可用的线程Map中获取到一个可用线程。
WorkerThread wt = (WorkerThread)availWorkers.removeFirst();
// 把获取到的可用线程放到busyWorkers中。
busyWorkers.add(wt);
//
wt.run(runnable);
} else {
// 如果线程池正在关闭,在新的其他工作线程执行Runnable
WorkerThread wt = new WorkerThread(this, threadGroup, "WorkerThread-LastJob", prio, isMakeThreadsDaemons(), runnable);
busyWorkers.add(wt);
workers.add(wt);
wt.start();
}
nextRunnableLock.notifyAll();
handoffPending = false;
}
return true;
}
//################# WorkerThread类的 ##################
public void run(Runnable newRunnable) {
synchronized(lock) {
if(runnable != null) {
throw new IllegalStateException("Already running a Runnable!");
}
runnable = newRunnable;
lock.notifyAll();
}
}
//################# WorkerThread类的 ##################
@Override
public void run() {
boolean ran = false;
while (run.get()) {
try {
synchronized(lock) {
while (runnable == null && run.get()) {
lock.wait(500);
}
if (runnable != null) {
ran = true;
runnable.run();
}
}
} catch (InterruptedException unblock) {
// do nothing (loop will terminate if shutdown() was called
try {
getLog().error("Worker thread was interrupt()'ed.", unblock);
} catch(Exception e) {
// ignore to help with a tomcat glitch
}
} catch (Throwable exceptionInRunnable) {
try {
getLog().error("Error while executing the Runnable: ",
exceptionInRunnable);
} catch(Exception e) {
// ignore to help with a tomcat glitch
}
} finally {
synchronized(lock) {
runnable = null;
}
// repair the thread in case the runnable mucked it up...
if(getPriority() != tp.getThreadPriority()) {
setPriority(tp.getThreadPriority());
}
if (runOnce) {
run.set(false);
clearFromBusyWorkersList(this);
} else if(ran) {
ran = false;
makeAvailable(this);
}
}
}
//if (log.isDebugEnabled())
try {
getLog().debug("WorkerThread is shut down.");
} catch(Exception e) {
// ignore to help with a tomcat glitch
}
}
// ##################### JobRunShell类 ################
// 这里才真正的执行了Job。
public void run() {
qs.addInternalSchedulerListener(this);
try {
OperableTrigger trigger = (OperableTrigger) jec.getTrigger();
JobDetail jobDetail = jec.getJobDetail();
do {
JobExecutionException jobExEx = null;
Job job = jec.getJobInstance();
try {
// 本身begin是没有做任何事的,但是如果有事务的话就要进行处理。
begin();
} catch (SchedulerException se) {
qs.notifySchedulerListenersError("Error executing Job (" + jec.getJobDetail().getKey() + ": couldn't begin execution.", se);
break;
}
// notify job & trigger listeners...
try {
if (!notifyListenersBeginning(jec)) {
break;
}
} catch(VetoedException ve) {
try {
CompletedExecutionInstruction instCode = trigger.executionComplete(jec, null);
qs.notifyJobStoreJobVetoed(trigger, jobDetail, instCode);
// 即使Trigger被否决,仍然需要检查它是否是Trigger的最终运行。
if (jec.getTrigger().getNextFireTime() == null) {
qs.notifySchedulerListenersFinalized(jec.getTrigger());
}
complete(true);
} catch (SchedulerException se) {
qs.notifySchedulerListenersError("Error during veto of Job (" + jec.getJobDetail().getKey() + ": couldn't finalize execution.", se);
}
break;
}
long startTime = System.currentTimeMillis();
long endTime = startTime;
//##############################################
// 执行Job
//##############################################
try {
log.debug("Calling execute on job " + jobDetail.getKey());
job.execute(jec);
endTime = System.currentTimeMillis();
} catch (JobExecutionException jee) {
endTime = System.currentTimeMillis();
jobExEx = jee;
getLog().info("Job " + jobDetail.getKey() + " threw a JobExecutionException: ", jobExEx);
} catch (Throwable e) {
endTime = System.currentTimeMillis();
getLog().error("Job " + jobDetail.getKey() + " threw an unhandled Exception: ", e);
SchedulerException se = new SchedulerException("Job threw an unhandled exception.", e);
qs.notifySchedulerListenersError("Job (" + jec.getJobDetail().getKey() + " threw an exception.", se);
jobExEx = new JobExecutionException(se, false);
}
jec.setJobRunTime(endTime - startTime);
// 通知所有的Job监听器,Job处理完成。 notify all job listeners
if (!notifyJobListenersComplete(jec, jobExEx)) {
break;
}
CompletedExecutionInstruction instCode = CompletedExecutionInstruction.NOOP;
// 更新trigger, update the trigger
try {
instCode = trigger.executionComplete(jec, jobExEx);
} catch (Exception e) {
SchedulerException se = new SchedulerException("Trigger threw an unhandled exception.", e);
qs.notifySchedulerListenersError("Please report this error to the Quartz developers.", se);
}
// 通知所有的trigger监听器,
if (!notifyTriggerListenersComplete(jec, instCode)) {
break;
}
// 更新job和trigger,或者重新执行job
if (instCode == CompletedExecutionInstruction.RE_EXECUTE_JOB) {
jec.incrementRefireCount();
try {
complete(false);
} catch (SchedulerException se) {
qs.notifySchedulerListenersError("Error executing Job (" + jec.getJobDetail().getKey() + ": couldn't finalize execution.", se);
}
continue;
}
try {
complete(true);
} catch (SchedulerException se) {
qs.notifySchedulerListenersError("Error executing Job ("+ jec.getJobDetail().getKey() + ": couldn't finalize execution.", se);
continue;
}
qs.notifyJobStoreJobComplete(trigger, jobDetail, instCode);
break;
} while (true);
} finally {
qs.removeInternalSchedulerListener(this);
}
}
1-2、启动流程
在上一节中Test类中调用了scheduler.start();启动线程。
// ######################## QuartzScheduler ############################
public void start() throws SchedulerException {
// 判断Quartz是否停止或者关闭,如果停止或者关闭抛出异常,Quartz是没有重启操作的。
if (shuttingDown|| closed) {
throw new SchedulerException("The Scheduler cannot be restarted after shutdown() has been called.");
}
// 获取所有scheduler listeners并进行通知
notifySchedulerListenersStarting();
if (initialStart == null) {
initialStart = new Date();
this.resources.getJobStore().schedulerStarted();
startPlugins();
} else {
resources.getJobStore().schedulerResumed();
}
//###########################
// 启动Quartz操作
//###########################
schedThread.togglePause(false);
getLog().info(
"Scheduler " + resources.getUniqueIdentifier() + " started.");
notifySchedulerListenersStarted();
}
// #################### QuartzSchedulerThread类 #########
void togglePause(boolean pause) {
synchronized (sigLock) {
// 把暂停设置为false,启动Quartz。
paused = pause;
if (paused) {
signalSchedulingChange(0);
} else {
// 通知所有被
sigLock.notifyAll();
}
}
}