# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance,if a different
# properties file is not explicitly specified.
#
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export:false
org.quartz.scheduler.rmi.proxy:false
org.quartz.scheduler.wrapJobExecutionInUserTransaction:false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount:10
org.quartz.threadPool.threadPriority:5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread:true
org.quartz.jobStore.misfireThreshold:60000
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
2020-01-0410:47:16.369[main] INFO org.quartz.impl.StdSchedulerFactory[1220]- Using default implementation for ThreadExecutor
2020-01-0410:47:16.421[main] INFO org.quartz.core.SchedulerSignalerImpl[61]- Initialized Scheduler Signaller of type:classorg.quartz.core.SchedulerSignalerImpl2020-01-0410:47:16.422[main] INFO org.quartz.core.QuartzScheduler[229]- Quartz Scheduler v.2.3.2 created.2020-01-0410:47:16.423[main] INFO org.quartz.simpl.RAMJobStore[155]- RAMJobStore initialized.2020-01-0410:47:16.424[main] INFO org.quartz.core.QuartzScheduler[294]- Scheduler meta-data: Quartz Scheduler (v2.3.2)'QuartzScheduler' with instanceId 'NON_CLUSTERED'
Scheduler class:'org.quartz.core.QuartzScheduler'- running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed:0
Using thread pool 'org.quartz.simpl.SimpleThreadPool'- with 10 threads.
Using job-store 'org.quartz.simpl.RAMJobStore'- which does not support persistence. and is not clustered.2020-01-0410:47:16.424[main] INFO org.quartz.impl.StdSchedulerFactory[1374]- Quartz scheduler 'QuartzScheduler' initialized from an externally provided properties instance.2020-01-0410:47:16.424[main] INFO org.quartz.impl.StdSchedulerFactory[1378]- Quartz scheduler version:2.3.22020-01-0410:47:16.426[main] INFO org.quartz.core.QuartzScheduler[2293]- JobFactory set to: org.springframework.scheduling.quartz.AdaptableJobFactory@3e9b10102020-01-0410:47:16.651[main] INFO org.quartz.core.QuartzScheduler[547]- Scheduler QuartzScheduler_$_NON_CLUSTERED started.
一月 04,202010:47:16 上午 org.springframework.scheduling.quartz.SchedulerFactoryBean startScheduler
信息: Starting Quartz Scheduler now
2020-01-0410:47:20.321[QuartzScheduler_Worker-1] INFO org.itstack.demo.DemoTask[11]- 定时处理用户信息任务:0/5****?2020-01-0410:47:25.001[QuartzScheduler_Worker-2] INFO org.itstack.demo.DemoTask[11]- 定时处理用户信息任务:0/5****?2020-01-0410:47:30.000[QuartzScheduler_Worker-3] INFO org.itstack.demo.DemoTask[11]- 定时处理用户信息任务:0/5****?2020-01-0410:47:35.001[QuartzScheduler_Worker-4] INFO org.itstack.demo.DemoTask[11]- 定时处理用户信息任务:0/5****?2020-01-0410:47:40.000[QuartzScheduler_Worker-5] INFO org.itstack.demo.DemoTask[11]- 定时处理用户信息任务:0/5****?
Process finished with exit code -1
publicvoidafterPropertiesSet()throws ClassNotFoundException, NoSuchMethodException {prepare();// Use specific name if given, else fall back to bean name.
String name =(this.name != null ?this.name :this.beanName);// Consider the concurrent flag to choose between stateful and stateless job.
Class<?> jobClass =(this.concurrent ? MethodInvokingJob.class: StatefulMethodInvokingJob.class);// Build JobDetail instance.
JobDetailImpl jdi =newJobDetailImpl();
jdi.setName(name);
jdi.setGroup(this.group);
jdi.setJobClass((Class) jobClass);
jdi.setDurability(true);
jdi.getJobDataMap().put("methodInvoker",this);this.jobDetail = jdi;postProcessJobDetail(this.jobDetail);}
privatebooleanaddTriggerToScheduler(Trigger trigger)throws SchedulerException {boolean triggerExists =(getScheduler().getTrigger(trigger.getKey())!= null);if(triggerExists &&!this.overwriteExistingJobs){returnfalse;}// Check if the Trigger is aware of an associated JobDetail.
JobDetail jobDetail =(JobDetail) trigger.getJobDataMap().remove("jobDetail");if(triggerExists){if(jobDetail != null &&!this.jobDetails.contains(jobDetail)&&addJobToScheduler(jobDetail)){this.jobDetails.add(jobDetail);}try{getScheduler().rescheduleJob(trigger.getKey(), trigger);}catch(ObjectAlreadyExistsException ex){if(logger.isDebugEnabled()){
logger.debug("Unexpectedly encountered existing trigger on rescheduling, assumably due to "+"cluster race condition: "+ ex.getMessage()+" - can safely be ignored");}}}else{try{if(jobDetail != null &&!this.jobDetails.contains(jobDetail)&&(this.overwriteExistingJobs ||getScheduler().getJobDetail(jobDetail.getKey())== null)){getScheduler().scheduleJob(jobDetail, trigger);this.jobDetails.add(jobDetail);}else{getScheduler().scheduleJob(trigger);}}catch(ObjectAlreadyExistsException ex){if(logger.isDebugEnabled()){
logger.debug("Unexpectedly encountered existing trigger on job scheduling, assumably due to "+"cluster race condition: "+ ex.getMessage()+" - can safely be ignored");}if(this.overwriteExistingJobs){getScheduler().rescheduleJob(trigger.getKey(), trigger);}}}returntrue;}
publicvoidstart()throws SchedulerException {if(shuttingDown|| closed){thrownewSchedulerException("The Scheduler cannot be restarted after shutdown() has been called.");}// QTZ-212 : calling new schedulerStarting() method on the listeners// right after entering start()notifySchedulerListenersStarting();if(initialStart == null){
initialStart =newDate();this.resources.getJobStore().schedulerStarted();startPlugins();}else{
resources.getJobStore().schedulerResumed();}// 唤醒线程
schedThread.togglePause(false);getLog().info("Scheduler "+ resources.getUniqueIdentifier()+" started.");notifySchedulerListenersStarted();}
QuartzSchedulerThread.run() & 执行过程
@Overridepublicvoidrun(){int acquiresFailed =0;// 只有调用了halt()方法,才会退出这个死循环while(!halted.get()){try{// 一、如果是暂停状态,则循环超时等待1000毫秒// wait a bit, if reading from job store is consistently failing (e.g. DB is down or restarting)..// 阻塞直到有空闲的线程可用并返回可用的数量int availThreadCount = qsRsrcs.getThreadPool().blockForAvailableThreads();if(availThreadCount >0){
List<OperableTrigger> triggers;long now = System.currentTimeMillis();clearSignaledSchedulingChange();try{// 二、获取acquire状态的Trigger列表,也就是即将执行的任务
triggers = qsRsrcs.getJobStore().acquireNextTriggers(
now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBat
acquiresFailed =0;if(log.isDebugEnabled())
log.debug("batch acquisition of "+(triggers == null ?0: triggers
}catch(){//...}if(triggers != null &&!triggers.isEmpty()){// 三:获取List第一个Trigger的下次触发时刻long triggerTime = triggers.get(0).getNextFireTime().getTime();// 四:获取任务触发集合
List<TriggerFiredResult> res = qsRsrcs.getJobStore().triggersFired(triggers);// 五:设置Triggers为'executing'状态
qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));// 六:创建JobRunShell
qsRsrcs.getJobRunShellFactory().createJobRunShell(bndle);// 七:执行Job
qsRsrcs.getThreadPool().runInThread(shell)continue;// while (!halted)}}else{// if(availThreadCount > 0)// should never happen, if threadPool.blockForAvailableThreads() follows concontinue;// while (!halted)}}catch(RuntimeException re){getLog().error("Runtime error occurred in main trigger firing loop.", re);}}
qs = null;
qsRsrcs = null;}
@Overridepublicvoidrun(){boolean ran =false;while(run.get()){try{synchronized(lock){while(runnable == null && run.get()){
lock.wait(500);}if(runnable != null){
ran =true;// 启动真正执行的内容,runnable就是JobRunShell
runnable.run();}}}cache(){//...}}//if (log.isDebugEnabled())try{getLog().debug("WorkerThread is shut down.");}catch(Exception e){// ignore to help with a tomcat glitch}}
protectedvoidexecuteInternal(JobExecutionContext context)throws JobExecutionException {try{// 反射执行业务代码
context.setResult(this.methodInvoker.invoke());}catch(InvocationTargetException ex){if(ex.getTargetException()instanceofJobExecutionException){// -> JobExecutionException, to be logged at info level by Quartzthrow(JobExecutionException) ex.getTargetException();}else{// -> "unhandled exception", to be logged at error level by QuartzthrownewJobMethodInvocationFailedException(this.methodInvoker, ex.getTargetException());}}catch(Exception ex){// -> "unhandled exception", to be logged at error level by QuartzthrownewJobMethodInvocationFailedException(this.methodInvoker, ex);}}