Timer篇与 Quartz篇

什么是定时任务调度

基于给定的时间点,给定的时间间隔或者给定的执行次数自动完成执行任务

在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了,随后的执行时间按照上一次实际执行完成的时间点进行计算。
      • 2、scheduleAtFixedRate方法
        • "fixed-delay"; 如果第一次执行时间被delay了,随后的执行时间按照上一次开始的时间点进行计算,并且为了赶上进度会多次执行任务,因此TimerTask中的执行体需要考虑同步
    • 任务执行所需的时间超出任务的执行周期间隔
      • 1、schedule方法
        • 下一次执行时间相对于上一次实际执行完成的时间点,因此执行时间会不断延后
      • 2、scheduleAtFixedRate方法
        • 下一次执行时间相对于上一次开始的时间点,因此执行时间不会延后,因此存在并发性

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简介

特点

  • 强大的调度功能(提供调度运行的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,任务调度现场数据并不会丢失。)
  • 灵活的运用方式(允许码农灵活的定义触发器的调度时间表,并可以对触发器和任务进行关联映射,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相同
    • 利用工具,在线生成

浅谈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:支持传入参数
Cron表达式.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容