什么是定时任务调度
基于给定的时间点,给定的时间间隔或者给定的执行次数自动完成执行任务
在Java中的定时调度工具
Timer Quartz
Timer和Quartz的区别
- 出身不同
- 能力区别 :对时间的控制上
- 底层机制 :Timer走后台进行定时任务,Quartz能使用多个线程执行定时任务
Timer简介
Timer的定义
有且仅有一个后台线程对多个业务线程进行定时定频率的调度。
主要构件
Timer:后台执行的线程
TimeTask:业务线程
TimerThread
TaskQueue
Timer的定时调度函数
schedule的四种用法
-
schedule(task,time)
- task:所要安排的任务
- time:首次执行任务的时间
- 作用:在时间等于或超过time的时候执行且仅执行一次task(如果time晚于现在的时间,schedule后台线程会一直等待,当时间等于time开始执行task里面的内容。time早于现在时间,schedule后台会立即执行task内容。)
-
schedule(task,time,period)
- task:所要安排的任务
- time:首次执行任务的时间
- period:执行一次task的时间间隔,单位是毫秒
- 作用:时间等于或者超过time时首次执行task,之后每隔period毫秒重复执行一次task
-
schedule(task,delay)
- task:所要安排的任务
- delay:执行任务前的延迟时间,单位是毫秒
- 作用:等待delay毫秒后执行且仅执行一次task
-
schedule(task,delay,period)
- task:所要安排的任务
- delay:执行任务前的延迟时间,单位是毫秒
- period:执行一次task的时间间隔,单位是毫秒
- 作用:等待delay毫秒后首次执行task,之后每隔period毫秒重复执行一次task
scheduleAtFixedRate的两种用法
-
scheduleAtFixedRate(task,time,period)
- task:所要安排的任务
- time:首次执行任务的时间
- period:执行一次task的时间间隔,单位是毫秒
- 作用:时间等于或者超过time时首次执行task,之后每隔period毫秒重复执行一次task
-
scheduleAtFixedRate(task,delay,period)
- task:所要安排的任务
- delay:执行任务前的延迟时间,单位是毫秒
- period:执行一次task的时间间隔,单位是毫秒
- 作用:等待delay毫秒后首次执行task,之后每隔period毫秒重复执行一次task
其他重要函数
TimerTask的两个重要函数
-
cancel()
- 作用:取消当前TimerTask里的任务
-
scheduledExecutionTime()
- 作用:返回此任务最近实际执行的已安排执行的时间
- 返回值:最近发生此任务执行安排的时间,为long型
Timer的其他函数
-
cancle()
- 作用:终止此计时器,丢弃
所有
当前已安排的任务(对群体进行秒杀的能力)
- 作用:终止此计时器,丢弃
-
purge()
- 作用:从此计时器的任务队列中移除所有
已取消
的任务
- 作用:从此计时器的任务队列中移除所有
schedule与scheduleAtFixedRate的区别
- 两种情况看区别
- 首次执行计划的时间早于当前的时间
- 1、schedule方法
- "fixed-delay"; 如果第一次执行时间被delay了,随后的执行时间按照
上一次实际执行完成的时间点
进行计算。
- "fixed-delay"; 如果第一次执行时间被delay了,随后的执行时间按照
- 2、scheduleAtFixedRate方法
- "fixed-delay"; 如果第一次执行时间被delay了,随后的执行时间按照
上一次开始的时间点
进行计算,并且为了赶上进度
会多次执行任务,因此TimerTask中的执行体需要考虑同步
- "fixed-delay"; 如果第一次执行时间被delay了,随后的执行时间按照
- 1、schedule方法
- 任务执行所需的时间超出任务的执行周期间隔
- 1、schedule方法
- 下一次执行时间相对于
上一次实际执行完成的时间点
,因此执行时间会不断延后
- 下一次执行时间相对于
- 2、scheduleAtFixedRate方法
- 下一次执行时间相对于
上一次开始的时间点
,因此执行时间不会延后
,因此存在并发性
- 下一次执行时间相对于
- 1、schedule方法
- 首次执行计划的时间早于当前的时间
Timer的缺陷
- 管理并发任务的缺陷
- Timer有且仅有一个线程去执行定时任务,如果存在多个任务,且任务时间过长,会导致执行效果与预期不符。
- 当任务抛出异常时的缺陷
- 如果TimerTask抛出RuntimeException,Timer会停止所有任务的运行。
- Timer的使用禁区
- 对时效性要求较高的多任务并发作业
- 对复杂的任务的调度
ScheduleExecutorService接口的用法
-
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
- command:执行线程
- initialDelay:初始化延时
- period:两次开始执行最小间隔时间
- unit:计时单位
-
scheduleWithFixedDelay(Runnable command, long initialDelay, long period, TimeUnit unit)
- command:执行线程
- initialDelay:初始化延时
- period:前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间)
- unit:计时单位
Quartz简介
- OpenSymphony提供的强大的开源任务调度框架(官网:http://www.quartz-scheduler.org/)
- 纯java实现,精细控制排程
特点
- 强大的调度功能(提供调度运行的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,任务调度现场数据并不会丢失。)
- 灵活的运用方式(允许码农灵活的定义触发器的调度时间表,并可以对触发器和任务进行关联映射,Quartz提供了主键式的监听器,各种插件,线程池等功能,支持任务和调度的多种组合方式,支持调度数据的多种存储方式)
- 分布式和集群能力
主要设计模式
Builder模式
Factory模式
组件模式
链式写法
体系结构
-
三个核心概念
- 调度器
- 任务
- 触发器
JobDetail(包含任务的实现类以及类的信息)
-
trigger(触发器,决定任务什么时候被调用)
- SimpleTrigger(执行类似Timer的时间上的操作,如定频率执行某一个task)
- CronTrigger(实现更复杂的业务逻辑)
scheduler(调度器,定时定频率执行JobDetail的信息,将Job和trigger绑定在一起)
重要组成
-
Job(接口)
- void execute(JobExecutionContext jex) 实现该接口定义运行任务
- JobExecutionContext 提供调度上下文的各种信息,Job运行时的信息就保存在JobExecutionContext里面的JobDataMap事例中
-
JobDetail
- Quartz在每次执行Job的时候都重新创建一个Job实例,所以不直接接受一个Job实例,相反它接受一个Job实现类,以便运行时通过newInstance的反射机制实例化Job。因此需要一个类来描述Job的实现类及其他相关的静态信息,如Job的名字,描述关联监听器等信息。
-
JobBuilder
- 用来定义和创建JobDetail的实例(JobDetail限定了只能是Job的实例)
-
JobStore(接口)
- 用来保存Job数据
- 实现类有:RAMJobStore,JobStoreTX,JobStoreCMT(后两个均将数据保存在数据库中,前一个保存在内存中)
-
Trigger
- 一个类,描述触发Job执行时的时间触发规则,主要有SimpleTrigger和CronTrigger两个子类,当仅需触发一个或者一固定时间间隔周期执行的时候,选择SimpleTrigger。CronTrigger通过Cron表达式定义各种复杂时间规则的调度方案。
-
TriggerBuilder
- 用来定义和创建触发器的实例
-
ThreadPool
- 整个线程池运行,scheduler使用该线程池作为任务运行的基础设施,任务通过共享线程池中的线程,提高运行的效率,解决并发的问题。
-
Scheduler
- 调度器,代表Quartz的一个独立运行容器,Trigger和JobDetail注射到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail也必须唯一且两者可以相同,因为类型不同。
- 定义了多个接口方法,允许外部通过组及名称访问它的控制容器中Trigger和JobDetail。
-
Calendar
- 一个Trigger可以和多个Calendar关联,以排除或包含某些时间点。
-
监听器
- JobListener,TriggerListener,SchedulerListener
浅谈Job & JobDetail
- Job定义
- Job接口非常容易实现,只有一个execute方法,类似TimerTask的run方法,在里面编写业务逻辑
- 源码
package org.quartz;
public interface Job {
void execute(JobExecutionContext context) throws JobExecutionException;
}
-
Job实例在Quartz中的生命周期
- 每次调度器执行job时,它在调用execute方法前会创建一个新的job实例。
- 当调用完成后,关联的job对象实例会被释放,释放的实例会被垃圾回收机制回收。
-
JobDetail
- JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例。
- 重要属性
- name:任务名称
- group:任务所属组,默认值DEFAULT
- jobClass:任务实现类
- jobDataMap:传参
浅谈JobExecutionContext
- JobExecutionContext是什么
- 当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法;
- Job能通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据。
浅谈JobDataMap
- JobDataMap是什么
- 在进行任务调度时JobDataMap存储在JobExecutionContext中,非常方便获取;
- JobDataMap可以用来装载任何可序列化的数据对象,当Job实例对象被执行时这些参数对象会传递给它;
- JobDataMap实现了JDK的Map接口,并且添加了一些非常方便的方法用来存取基本数据类型。
- 获取JobDataMap的两种方式
从Map中直接获取
Job实现类中添加setter方法对应JobDataMap的键值(Quartz框架默认的JobFactory实现类在初始化Job实例对象时会自动地调用这些setter方法)
浅谈Trigger
Quartz中的触发器用来告诉调度程序作业什么时候触发。即Trigger对象是用来触发执行Job的。
-
触发器通用属性
- JobKey:表示Job实例的标识,触发器被触发时,该指定的Job实例会执行。
- StartTime:表示触发器的时间表
首次被触发
的时间,它的值的类型是Java.util.Date。 - EndTime:指定触发器的
不再被触发的时间
,它的值的类型是Java.util.Date。
SimpleTrigger
-
SimpleTrigger的作用
- 在一个
指定时间段
内执行一次
作业任务,或是在指定的时间间隔
内多次执行
作业任务。
- 在一个
-
需要注意的点
- 重复次数可以为0,正整数或是SimpleTrigger.REPEAT_INDEFINITELY常量值。
- 重复执行间隔必须为0或长整数。
- 一旦被指定了endTime参数,那么它会覆盖重复次数参数的效果。
CronTrigger
-
CronTrigger的作用
- 基于日历的作业调度器,而不是像SimpleTrigger那样精确指定间隔时间,比SimpleTrigger更常用。
-
Cron表达式
- 用于配置CronTrigger实例。是有
7个子表达式
组成的字符串,描述了时间表的详细信息。 - 格式:[秒] [分] [小时] [日] [月] [周] [年]
- ,:或的关系;-:至(between)的关系;*:每的关系;/:每天的几分钟执行。
- 'L'和'W'可以组合使用
- 周字段英文字母不区分大小写即MON与mon相同
- 利用工具,在线生成
- 用于配置CronTrigger实例。是有
浅谈Scheduler
- Scheduler - 工程模式
- 所有的Scheduler实例应该由SchedulerFactory来创建
- 两个实现类:StdSchedulerFactory(常用)和 DirectSchedulerFactory
- Scheduler的创建方式
SchedulerFactory sfact = new StdSchedulerFactory();
Scheduler scheduler = sfact.getScheduler();
DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();
Scheduler scheduler = factory.getScheduler();
-
StdSchedulerFactory
- 使用一组参数(Java.util.Properties)来创建和初始化Quartz调度器
- 配置参数一般存储在quartz.properties中
- 调用getScheduler方法就能创建和初始化调度器对象
-
Scheduler的主要函数
- Date schedulerJob(JobDetail jobDetail, Trigger trigger)
- void start()
- void standby() 暂时挂起
- void shutdown() 完全关闭
quartz.properties
- 文档的位置和加载顺序
- 组成部分
- 调度器属性
-
org.quartz.scheduler.instanceName
属性用来区分特定的调度器实例
,可以按照功能用途来给调度器起名。 -
org.quartz.scheduler.instanceId
属性和前者一样,也允许任何字符串,但这个值必须是在所有调度器实例中是唯一
的,尤其是在一个集群中,作为集群的唯一key。假如你想Quartz帮你生成这个值的话,可以设置为AUTO。
-
- 线程池属性(直接关系Quartz后台处理现场的性能)
- threadCount:决定Quartz需要有多少个工作者线程被创建,用来处理Trigger。至少为1。
- threadPriority:设置工作者线程优先级,优先级别高的线程比级别低的线程更优先得到执行。
- org.quartz.threadPool.class:是一个实现了org.quartz.spi.ThreadPool接口的类的全限名称。Quartz自带该线程池实现,org.quartz.spi.ThreadPool它能够满足大多数用户需求,具备简单行为,经过很好的测试,在调度器的生命周期中提供固定大小的线程池,可根据需求创建自己的线程池实现。
- 作业存储设置
- 描述了在调度器实例的生命周期中,Job和Trigger信息是如何被存储的。
- 插件配置
- 满足特定需求用到的Quartz插件的配置。
- 调度器属性
使用Quartz配置作用
- 两种方式
- MethodInvokingJobDetailFactoryBean:调用特定bean的方法是很方便
- JobDetailFactoryBean:支持传入参数