为什么需要quartz
quartz是一个调度框架,支持简单调度和定时调度。支持多任务持久化处理。
特性一:触发处理
解决的问题:
通常我们进行一个任务调度,会对一系列条件进行判断,比如一个定时执行的任务需要在每天12点进行执行,判断程序触发的话可以通过while循环来判断当前时间是否到达指定的时间,当条件满足时执行任务。如果有多个程序需要执行,我们就需要开启多个线程进行轮训。这样每次cpu进行多个时间切片进到线程去判断条件是否满足,满足后在继续执行任务,对cpu来说是个浪费。
获取trrgers:
quartz对触发的处理逻辑:可以选择把任务保存在数据库中。建立一个任务时,首先需要计算下一次的触发时间,也就是qrtz_triggers表中的的NEXT_FIRE_TIME,然后保存到数据库中,添加一个job的时序图如下。
在schedule初始化时,同时开启一个线程,这个线程会对当前时间和qrtz_triggers表中所有记录的NEXT_FIRE_TIME进行比较,如果大于该时间则执行该trrigers记录对应的任务,达到了只需要一个线程就可以对多个任务执行条件进行判断。具体代码获取到达触发条件triggers的代码参见QuartzSchedulerThread.java类中的代码
triggers = qsRsrcs.getJobStore().acquireNextTriggers(
now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow());
这个方法实际执行了StdJDBCConstants中的语句
String SELECT_NEXT_TRIGGER_TO_ACQUIRE = "SELECT "
+ COL_TRIGGER_NAME + ", " + COL_TRIGGER_GROUP + ", "
+ COL_NEXT_FIRE_TIME + ", " + COL_PRIORITY + " FROM "
+ TABLE_PREFIX_SUBST + TABLE_TRIGGERS + " WHERE "
+ COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST
+ " AND " + COL_TRIGGER_STATE + " = ? AND " + COL_NEXT_FIRE_TIME + " <= ? "
+ "AND (" + COL_MISFIRE_INSTRUCTION + " = -1 OR (" +COL_MISFIRE_INSTRUCTION+ " != -1 AND "+ COL_NEXT_FIRE_TIME + " >= ?)) "
+ "ORDER BY "+ COL_NEXT_FIRE_TIME + " ASC, " + COL_PRIORITY + " DESC";
可以看到 quartz把trigger从jobdetai中拆分出来,利用了正交性避免触发与任务的耦合,但是看其源码,
trigers与数据库的代码耦合性却很高,不好对数据库操作进行扩展。
随后对数据库查询到的resultSet中的trriger进行job查找,并执行相关的任务