Quartz任务调度框架

Quartz 基本概念及原理

作为一个优秀的开源调度框架,Quartz 具有以下特点:
1、强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;
2、 灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;
3、分布式和集群能力,Terracotta 收购后在原来功能基础上作了进一步提升。本文暂不讨论该部分内容。

作为 Spring 默认的调度框架,Quartz 很容易与 Spring 集成实现灵活可配置的调度功能。

Quartz专用词汇:
scheduler :任务调度器
trigger :触发器,用于定义任务调度时间规则
job :任务,即被调度的任务
misfire :错过的,指本来应该被执行但实际没有被执行的任务调度

Quartz 任务调度的基本实现原理

Quartz 任务调度的核心元素是 scheduler, trigger 和 job,其中 trigger 和 job 是任务调度的元数据, scheduler 是实际执行调度的控制器

trigger 是用于定义调度时间的元素,即按照什么时间规则去执行任务。
Quartz 中主要提供了四种类型的 trigger:
SimpleTrigger,CronTirgger,DateIntervalTrigger,和 NthIncludedDayTrigger。

job 用于表示被调度的任务
两种类型:无状态的(stateless)和有状态的(stateful)。对于同一个 trigger 来说,有状态的 job 不能被并行执行,只有上一次触发的任务被执行完之后,才能触发下一次执行。
Job 主要有两种属性:volatility 和 durability,其中 volatility 表示任务是否被持久化到数据库存储,而 durability 表示在没有 trigger 关联的时候任务是否被保留。两者都是在值为 true 的时候任务被持久化或保留。job : trigger -> 1 : n

scheduler 由 scheduler 工厂创建:DirectSchedulerFactory 或者 StdSchedulerFactory。StdSchedulerFactory使用广泛。

Scheduler 主要有三种:RemoteMBeanScheduler, RemoteScheduler 和 StdScheduler

Quartz 核心元素关系图
Quartz任务调度框架_第1张图片

在 Quartz 中,有两类线程,Scheduler调度线程和任务执行线程,其中任务执行线程通常使用一个线程池维护一组线程。

Quartz 线程视图
Quartz任务调度框架_第2张图片

Scheduler 调度线程主要有两个: 执行常规调度的线程,和执行 misfired trigger 的线程。

Quartz 调度线程流程图
Quartz任务调度框架_第3张图片

企业级开发中的常见应用

一、如何使用不同类型的 Trigger

SimpleTrigger

SimpleTrigger 一般用于实现每隔一定时间执行任务,以及重复多少次,如每 2 小时执行一次,重复执行 5 次。

SimpleTrigger 内部实现机制是通过计算间隔时间来计算下次的执行时间,这就导致其不适合调度定时的任务。

注意这里就会有一个问题,即当有 misfired 的任务并且恢复执行时,该执行时间是随机的(取决于何时执行 misfired 的任务,例如某天的 3:00PM)。这会导致之后每天的执行时间都会变成 3:00PM,而不是我们原来期望的 1:00AM。

CronTirgger

类似于 LINUX 上的任务调度命令 crontab,即利用一个包含 7 个字段的表达式来表示时间调度方式。对于涉及到星期和月份的调度,CronTirgger 是最适合的
Cron 表达式包括以下 7 个字段:
秒、分、小时、月内日期、月、周内日期、年(可选字段)

Cron 触发器利用一系列特殊字符:

  • 反斜线(/)字符表示增量值

    秒字段中“5/15”代表从第 5 秒开始,每 15 秒一次。

  • 问号(?)字符和字母 L 字符只有在月内日期和周内日期字段中可用。

    问号表示这个字段不包含具体值。所以,如果指定月内日期,可以在周内日期字段中插入“?”,表示周内日期值无关紧要。字母 L 字符是 last 的缩写。放在月内日期字段中,表示安排在当月最后一天执行。在周内日期字段中,如果“L”单独存在,就等于“7”,否则代表当月内周内日期的最后一个实例。所以“0L”表示安排在当月的最后一个星期日执行
    在月内日期字段中的字母(W)字符把执行安排在最靠近指定值的工作日。

  • 井号(#)字符为给定月份指定具体的工作日实例

  • 星号(*)字符是通配字符,表示该字段可以接受任何可能的值。

DateIntervalTrigger

Quartz 1.7 之后的版本加入的,其最适合调度类似每 N(1, 2, 3…)小时,每 N 天,每 N 周等的任务。DateIntervalTrigger 不会受到我们上面说到的 misfired 任务的影响,也不会受到 DST(Daylight Saving Time, 即中国的夏令时)调整的影响。

NthIncludedDayTrigger

NthIncludedDayTrigger 的用途比较简单明确,即用于每隔一个周期的第几天调度任务,例如,每个月的第 3 天执行指定的任务。

二、使用有状态(StatefulJob)还是无状态的任务(Job)

在 Quartz 中,Job 是一个接口,企业应用需要实现这个接口以定义自己的任务。
任务分为有状态和无状态两种。
实现 Job 接口的任务缺省为无状态的。Quartz 中还有另外一个接口 StatefulJob

Quartz 中 Job 接口定义
Quartz任务调度框架_第4张图片

无状态任务一般指可以并发的任务,即任务之间是独立的,不会互相干扰

三、如何设置 Quartz 的线程池和并发任务

Quartz 中自带了一个线程池的实现:SimpleThreadPool
配置参数:org.quartz.threadPool.threadCount : 设定线程池的线程数量

在应用中,如果有更好的线程池,则可以在配置文件中通过下面参数替换 SimpleThreadPool:org.quartz.threadPool.class = myapp.GreatThreadPool

这里写图片描述

Quartz任务调度框架_第5张图片

你可能感兴趣的:(web开发框架,Web开发)