问题
- StatefulJob的实现:持久化JobDataMap到JobStore
- 在任务执行的时候如果前一个任务还没被执行完怎么办?如果是无状态的job,则只要线程允许就可以执行;而StatefulJob不可以,第二个trigger会被阻塞(阻塞的实现方式)。
- 中断job -p47
- end
优点
更复杂的定时调度逻辑:支持cron表达式、可以将任务进行分组、
线程池:
声明式的部署:怎样读取xml
数据库持久化:
支持集群:通过数据库进行同步
调度器可以暂停:怎么暂停?
RMI调用:
- 核心类抽象
-
- Job相关抽象
Job:
JobDetail:getName\getJobDataMap
JobDataMap
-
- 框架相关
JobexecutionContext:
Scheduler:
Trigger
JobStore
QuartzSchedulerThread \ triggerFiredBundle JobRunShell – p51
QuartzSchedulerResources
calendar:与java的设计目的不同,quartz中的calendar是为了在trigger中屏蔽“假日”
-
- 备注
- job和jobDetail有什么区别:job只描述整个作业的运行逻辑,但是job在运行时可能会被赋予一些其他的属性(比如为job的某次运行赋予一个name,job在运行时属于某一个组,job运行时需要的参数)
- 核心方法
QuartzSchedulerThread.run();
scheduler.scheduleJob(jobDetail, trigger);
- 逻辑实现
- 和任务相关的核心抽象有三个:Job(任务的逻辑)、JobDetail(任务执行时的参数、名字、group等)、JobRunShell(任务的执行环境,scheduler等)。还有与调度时机相关的trigger和管理整个线程调度的scheduler。
- 系统启动之后会有一个核心线程QuartzSchedulerThread,里面用一个大的循环不断根据trigger来触发Job,但是Job被触发后是运行在另外的线程池中。
- 核心调度线程QuartzSchedulerThread的伪代码
while(!shutdown){
//检测有没有暂停的逻辑
while(pause){
lock.wait(1s);
}
if(hasAvailableThread){//有可以用来执行的线程
getNextTrigger();//
lock.wait(triggerTime-now);//等待执行太远的trigger应该也不会取出来,否则等待执行阻塞了新部署的job
ThreadPool.runJob;
}
}
- 线程池的实现:quartz的线程池虽然和java中的线程池的复用思想是一致的,但是提供的接口是有些许差别,所以实现使用的是自己实现的SimpleThreadPool。主要思想就是有两个链表availWorkers和busyWorkers,维护这两个链表。
怎样知道Thread内的逻辑执行完毕?quartz覆写了Thread的run方法,在run方法的最后标记该线程执行完毕。
- Job的初始化- SimpleJobFactory:每一次的任务执行都会对应一个新的Job实例,所以开发者是不能提前new Job的,所以quartz会通过反射的机制产生Job。
- Trigger和Job的关联是通过Trigger的JobName实现的,所以一个trigger只能关联一个job,一个job却可以关联多个trigger。
- Trigger的定时触发是怎么实现的?
在JobStore中使用TreeSet存储着系统的所有trigger(根据trigger的优先级排序)
当有空闲的Job执行线程时,QuartzSchedulerThread调用jobStore. acquireNextTrigger
jobStore按顺序遍历trigger,调用trigger. getNextFireTime,如果到了trigger的执行时间就返回给QuartzSchedulerThread执行。此时可能有trigger错过了正规的执行时间(有一个阈值,默认是5ms)则通知错误处理的Listener。
- 其他
trigger.computeFirstFireTime