任务调度框架 Quartz 一文读懂
1、Quartz 简介
Quartz是OpenSymphony
开源组织在Job scheduling
领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer
。但是相较于Timer, Quartz增加了很多功能:
持久性作业 - 就是保持调度定时的状态;
作业管理 - 对调度作业进行有效的管理;
官方文档:
http://www.quartz-scheduler.org/documentation/
http://www.quartz-scheduler.org/api/2.3.0/index.html
2、Quartz 快速入门
Quartz 核心概念
Quartz 的核心类由以下三部分构成:
任务 Job : 需要实现的任务类,实现
execute()
方法,执行后完成任务。触发器 Trigger : 包括
SimpleTrigger
和CronTrigger
。调度器 Scheduler : 任务调度器,负责基于
Trigger
触发器,来执行 Job任务。
关系结构图:
Quartz 快速入门
第一步:创建Maven项目,添加Quartz 定时任务框架依赖Jar包
<!-- 核心包 --><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version></dependency><!-- 工具包 --><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId><version>2.3.0</version></dependency>
第二步:自定义Job
package com.zzg.quartz.job;import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("定时任务执行了!");}
}
第三步:测试方法实现创建调度器、jobDetail 实例、trigger 实例、执行。
package com.zzg.quartz;import com.zzg.quartz.job.MyJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;import java.util.concurrent.TimeUnit;import static org.quartz.SimpleScheduleBuilder.simpleSchedule;/*** 核心步骤说明:* 1.创建调度器 Scheduler* * 2.创建JobDetail实例,并与MyJob类绑定* * 3.构建Trigger实例,指定时间执行* * 4.执行,开启调度器*/
public class QuartzTest {public static void main(String[] args) throws SchedulerException, InterruptedException {// 1.创建调度器 SchedulerSchedulerFactory factory = new StdSchedulerFactory();Scheduler scheduler = factory.getScheduler();// 2.创建JobDetail实例,并与MyJob类绑定(Job执行内容)JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").build();// 3.构建Trigger实例,每隔30s执行一次Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(30).repeatForever()).build();// 4.执行,开启调度器scheduler.scheduleJob(job, trigger);System.out.println(System.currentTimeMillis());scheduler.start();//主线程睡眠1分钟,然后关闭调度器TimeUnit.MINUTES.sleep(1);scheduler.shutdown();System.out.println(System.currentTimeMillis());}
}
Quartz 核心类
JobDetail
JobDetail 的作用是绑定 Job,是一个任务实例,它为 Job 添加了许多扩展参数。
主要字段 | 涵义、作用 |
---|---|
name | 任务名称 |
group |
任务分组,默认分组 DEFAULT
|
jobClass |
任务类,就是上面 Demo 中的 MyJob 的路径
|
jobDataMap | 任务参数信息。JobDetail、Trigger 都可以使用 JobDataMap 来设置一些参数或信息。 |
每次Scheduler
调度执行一个Job的时候,首先会拿到对应的Job,然后创建该Job实例,再去执行Job中的execute()
的内容,任务执行结束后,关联的Job对象实例会被释放,且会被JVM GC清除。
疑问:为什么设计成JobDetail + Job,不直接使用Job
JobDetail 定义的是任务数据,而真正的执行逻辑是在Job中。
这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而
JobDetail & Job
方式,Sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以 规避并发访问 的问题。
JobExecutionContext
当
Scheduler
调用一个 job,就会将JobExecutionContext
传递给 Job 的execute()
方法;Job 能通过
JobExecutionContext
对象访问到 Quartz 运行时候的环境以及 Job 本身的明细数据。
任务实现的 execute()
方法,可以通过 context 参数获取。
public interface Job {void execute(JobExecutionContext context)throws JobExecutionException;
}
在 JobDetail 建造过程中,可以使用如下方法:
// 2.创建JobDetail实例,并与MyJob类绑定(Job执行内容)JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1")// 定义任务添加自定义参数.usingJobData("quartz", "quartz 自定义参数").build();
在 Trigger建造过程中,可以使用如下方法:
// 3.构建Trigger实例,每隔30s执行一次Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")// Trigger 添加自定义参数.usingJobData("trigger", "trigger 自定义参数").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(30).repeatForever()).build();
在 自定义MyJob中的execute
方法中获取:
package com.zzg.quartz.job;import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {Object group = context.getTrigger().getJobDataMap().get("trigger");Object group1 = context.getJobDetail().getJobDataMap().get("quartz");System.out.println("定时任务执行了!");}
}
Job状态参数
有状态的 job 可以理解为多次 job调用期间可以持有一些状态信息,这些状态信息存储在 JobDataMap
中。
而默认的无状态 job,每次调用时都会创建一个新的 JobDataMap
。
自定义MyJob
//多次调用 Job 的时候,将参数保留在 JobDataMap
@PersistJobDataAfterExecution
public class JobStatus implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {long count = (long) context.getJobDetail().getJobDataMap().get("count");System.out.println("当前执行,第" + count + "次");context.getJobDetail().getJobDataMap().put("count", ++count);}
}
在 JobDetail 建造过程中,携带拓展参数
JobDetail job = JobBuilder.newJob(JobStatus.class).withIdentity("statusJob", "group1").usingJobData("count", 1L).build();
Trigger
定时启动/关闭
Trigger
可以设置任务的开始结束时间, Scheduler
会根据参数进行触发。
Calendar instance = Calendar.getInstance();
Date startTime = instance.getTime();
instance.add(Calendar.MINUTE, 1);
Date endTime = instance.getTime();// 3.构建Trigger实例
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")// 开始时间.startAt(startTime)// 结束时间.endAt(endTime).build();
在 job 中也能拿到对应的时间,并进行业务判断
public void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("任务执行。。。");System.out.println(context.getTrigger().getStartTime());System.out.println(context.getTrigger().getEndTime());
}
SimpleTrigger
比较简单的一类触发器,用它能实现很多基础的应用。使用它的主要场景包括:
在指定时间段内,执行一次任务
最基础的 Trigger 不设置循环,设置开始时间。
在指定时间段内,循环执行任务
在 快速入门代码基础上加上循环间隔。可以指定 永远循环、运行指定次数
TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(30).repeatForever())
withRepeatCount(count)` 是重复次数,实际运行次数为 `count+1
TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(30).withRepeatCount(5))
- 立即开始,指定时间结束
这个省略...
CronTigger
CronTrigger
是基于日历的任务调度器,在实际应用中更加常用。
虽然很常用,但是知识点都一样,只是可以通过表达式来设置时间而已。
使用方式就是绑定调度器时换一下:
TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ?"))
Cron 表达式请参考:Cron表达式学习
Quartz 与Spring Boot 集成
请参考:Spring Boot2.x + Quartz 定时任务模块
任务调度框架 Quartz 一文读懂相关推荐
- 量化框架backtrader之一文读懂observer观测器
简介 Backtrader observer观测器主要用于观察策略运行过程中的各个状态指标,如资金.买卖点等,在调用cerebro.plot()后可以方便地可视化状态指标的变化情况,如下图展示的Bro ...
- 量化框架backtrader之一文读懂Analyzer分析器
诺贝尔奖获得者威廉夏普 简介 策略绩效评价是量化交易很重要的一环,投资不仅需要了解策略的收益率, 也需要了解策略的风险.backtrader提供多种analyzer分析器,可以输出多种绩效指标,用来分 ...
- hdfs文档存储服务器,一文读懂HDFS分布式存储框架分析
一文读懂HDFS分布式存储框架分析 HDFS是一套基于区块链技术的个人的数据存储系统,利用无处不在的私人PC存储空间及便捷的网络为个人提供数据加密存储服务,将闲置的存储空间利用起来,服务于正处于爆发期 ...
- hdfs读写流程_一文读懂HDFS分布式存储框架分析
一文读懂HDFS分布式存储框架分析 HDFS是一套基于区块链技术的个人的数据存储系统,利用无处不在的私人PC存储空间及便捷的网络为个人提供数据加密存储服务,将闲置的存储空间利用起来,服务于正处于爆发期 ...
- 一文读懂大数据平台——写给大数据开发初学者的话!
一文读懂大数据平台--写给大数据开发初学者的话! 文|miao君 导读: 第一章:初识Hadoop 第二章:更高效的WordCount 第三章:把别处的数据搞到Hadoop上 第四章:把Hado ...
- 从根上理解高性能、高并发(七):深入操作系统,一文读懂进程、线程、协程
本文引用了"一文读懂什么是进程.线程.协程"一文的主要内容,感谢原作者的无私分享. 1.系列文章引言 1.1 文章目的 作为即时通讯技术的开发者来说,高性能.高并发相关的技术概念早 ...
- 一文读懂Faster RCNN
来源:信息网络工程研究中心本文约7500字,建议阅读10+分钟 本文从四个切入点为你介绍Faster R-CNN网络. 经过R-CNN和Fast RCNN的积淀,Ross B. Girshick在20 ...
- 一文读懂EfficientDet
一文读懂EfficientDet. 今年年初Google Brain团队在 CVPR 2020 上发布了 EfficientDet目标检测模型, EfficientDet是一系列可扩展的高效的目标检测 ...
- 一文读懂序列建模(deeplearning.ai)之序列模型与注意力机制
https://www.toutiao.com/a6663809864260649485/ 作者:Pulkit Sharma,2019年1月21日 翻译:陈之炎 校对:丁楠雅 本文约11000字,建议 ...
最新文章
- Win7开机密码破解
- python脚本实例手机端-手机APP自动签到-python实现 - 运维之路
- 关于Crypto.PublicKey.RSA,在generate后无法被赋值问题
- 电脑销售渠道_为园区企业搭建服务麦格米特,长城电脑等企业产业链销售渠道...
- 浅谈数组常见遍历方法
- 会java学scala多久_Scala中超时的未来
- lightoj 1044 - Palindrome Partitioning(需要优化的区间dp)
- [Unity] Animation Blend Tree 中混合值变化时部分骨骼错误旋转 360 度的解决办法:将 Humanoid 改成 Generic
- 如何基于列值从DataFrame中选择行?
- css入门自学笔记1
- java年龄不能超过120,systemd 代码行数超过 120 万,创始人贡献的 commits 最多
- PCL_三维点云拼接融合/点云粗配准/点云精配准
- 数据库课程设计(饭店点餐系统)
- 计算机端口25,在Windows 下关闭21\23\25端口的方法 -电脑资料
- windows电脑桌面旋转快捷键
- 如何让OpenwrtX86和win7双系统共存在一块硬盘
- iOS之ffmpeg开发音视频编解码概要、SDL
- CreateDC与CreateCompatibleDC建立的HDC有何不同?
- word中表格出现断线的问题
- Opencv学习笔记完整版
热门文章
- 【教程】探究暴风影音视频截图黑屏原因
- 2014总结_习惯累积沉淀_新浪博客
- GPS从入门到放弃(五) --- GPS导航电文
- 关于软件项目经理的一些问题
- django manage.py扩展自定义命令
- GOTS认证辅导,GOTS对运动用品格外宽容,最多含有25%的合成或再生纤维
- LightSwitch登录界面如何设置背景
- 对接支付宝人脸识别和获取用户信息接口
- vue-cli 3.0版本,配置代理Proxy,不同环境不同target(生产环境,uat环境和本地环境的配置)...
- 若依框架中超级管理员的判断