任务调度是指基于给定时间点,给定时间间隔或者给定执行次数自动执行任务。
Java中几种任务调度方式
- Timer
- ScheduledExecutor
Timer
使用 Timer 实现任务调度的核心类是 Timer 和 TimerTask。其中 Timer 负责设定 TimerTask 的起始与间隔执行时间。使用者只需要创建一个 TimerTask 的继承类,实现自己的 run 方法,然后将其丢给 Timer 去执行即可。
Timer 的设计核心是一个 TaskList 和一个 TaskThread。Timer 将接收到的任务丢到自己的 TaskList 中,TaskList 按照 Task 的最初执行时间进行排序。TimerThread 在创建 Timer 时会启动成为一个守护线程。这个线程会轮询所有任务,找到一个最近要执行的任务,然后休眠,当到达最近要执行任务的开始时间点,TimerThread 被唤醒并执行该任务。之后 TimerThread 更新最近一个要执行的任务,继续休眠。
Timer 是一种定时器工具,用来在一个后台线程计划执行指定任务,而 TimerTask 一个抽象类,它的子类代表一个可以被 Timer 计划的任务。
Timer 的缺陷:
1、Timer 管理时间延迟缺陷
但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。还有Timer 是基于绝对时间的,对系统时间比较敏感。
2、Timer 抛出异常缺陷
如果 TimerTask 抛出 RuntimeException,Timer 会终止所有任务的运行。
ScheduledExecutorService
对于 Timer 的缺陷,我们可以考虑 ScheduledThreadPoolExecutor 来替代。Timer 是基于绝对时间的,对系统时间比较敏感,而 ScheduledThreadPoolExecutor 则是基于相对时间;Timer 是内部是单一线程,而 ScheduledThreadPoolExecutor 内部是个线程池,所以可以支持多个任务并发执行。
其设计思想是,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。需要注意的是,只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态。
用 ScheduledExecutor 和 Calendar 实现复杂任务调度
Timer 和 ScheduledExecutor 都仅能提供基于开始时间与重复间隔的任务调度,不能胜任更加复杂的调度需求。比如,设置每星期二的 16:38:10 执行任务。该功能使用 Timer 和 ScheduledExecutor 都不能直接实现,但我们可以借助 Calendar 间接实现该功能。
XXL-JOB
http://www.xuxueli.com/xxl-job/#/?id=%E3%80%8A%E5%88%86%E5%B8%83%E5%BC%8F%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E5%B9%B3%E5%8F%B0xxl-job%E3%80%8B
xxl-job由调度中心和执行器两部分组成,调度中心负责任务的调度,执行器负责执行任务。调度中心后台,支持配置任务,控制任务,查看任务运行日志等功能。
执行器:任务的绑定的执行器,任务触发调度时将会自动发现注册成功的执行器
描述:任务的描述信息,便于任务管理
路由策略:当执行器集群部署时,提供丰富的路由策略,包括,
第一个:固定选择第一个机器;
最后一个:固定选择最后一个机器;
轮询:执行器循环执行
随机:随机选择在线的机器
一致性HASH:每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上
最不经常使用:使用频率最低的机器优先被选举
最近最久未使用:轮询的倒序选用
故障转移:按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度
忙碌转移:按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度
Cron:触发任务执行的Cron表达式
运行模式:任务以JobHandler方式维护在执行器端,需要结合“JobHandler”属性匹配执行器中任务
JobHandler:运行模式为“Bean”时生效,对应执行器中新开发的JobHandler类@JobHandler注解自定义的value值
子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。
阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,
单机串行:调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行;
丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会将丢弃并标记为失败;
覆盖之前调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列,然后运行本地调度任务失败处理策略:
失败告警:调度失败时,将会触发失败报警,如发送报警邮件;
失败重试:调度失败时,将会主动进行一次失败重试调度,重试调度后仍然失败将会触发失败告警。注意当任务以failover方式路由时,每次失败重试将会触发新一轮路由;
执行参数:任务执行所需的参数,多个参数时用逗号分隔,任务执行时将会把多个参数转换为数组传入
报警邮件:任务调度失败时邮件通知的邮箱地址,支持配置多邮箱地址,配置多个邮箱地址时用逗号分隔
网友评论