前言

linux中的cron可以是任务调度的初形。随着任务的复杂性及分布式需求,cron显的力不从心。Quartz是经典的作业调度框架。

Quartz的基础

在深入研究之初,先仿照quartz的原理,设计一个简单的作业调度器。

  1. 先看job类,这个类,非常简单,只有一个execute方法,该方法是job具体执行的内容:
public class Job {public void execute(Map<String, String> jobData) {System.out.println("定时器任务执行" + new Date(System.currentTimeMillis()));System.out.println("参数值"+jobData.get("jobName"));}
}
  1. jobdetail类,该类是对具体job类的封装,包括jobName(任务标识),job执行需要的运行时参数jobdata
public class JobDetail {private Class<? extends Job> clz;private String jobName;private Map<String, String> jobData;public JobDetail(Class<? extends Job> clz, String jobName) {this.clz = clz;this.jobName = jobName;this.jobData = new HashMap<>();this.jobData.put("jobName", this.jobName);}public String getJobName(){return this.jobName;}public void executeJob(){try {clz.newInstance().execute(jobData);} catch (Exception e) {e.printStackTrace();}}
}
  1. trigger类,记录下次运行作业的时间和运行job的key
public class Trigger implements Comparable<Trigger>{private String jobKey;private long nextFireTime;public Trigger(long nextFireTime) {this.nextFireTime = nextFireTime;}// 用于根据触发时间排序@Overridepublic int compareTo(Trigger o) {return (int)( this.nextFireTime - o.nextFireTime);}public void setJobKey(String jobKey){this.jobKey = jobKey;}public String getJobKey() {return jobKey;}public long getNextFireTime() {return nextFireTime;}
}
  1. scheduler类,最重要的类,用来启动和停止框架
public class Scheduler {private Map<String, JobDetail> jobMap = new HashMap<>();private TreeSet<Trigger> triggerList = new TreeSet<>();private SchedulerThread schedulerThread = new SchedulerThread();public void schedulerJob(JobDetail jobDetail, Trigger trigger){jobMap.put(jobDetail.getJobName(),jobDetail);trigger.setJobKey(jobDetail.getJobName());triggerList.add(trigger);}public void start(){schedulerThread.start();}public void stop(){schedulerThread.halt();}
}
  1. scheduler的执行是在scheduler的schedulerThread中执行
public class SchedulerThread extends Thread {private boolean shutDown = false;@Overridepublic void run() {while (!shutDown){Trigger trigger = triggerList.pollFirst();if(trigger == null){try {Thread.sleep(100);} catch (InterruptedException e) {}continue;}long cur = System.currentTimeMillis();long next = trigger.getNextFireTime();if(cur <  next){try {Thread.sleep(next - cur);} catch (InterruptedException e) {}}JobDetail jobDetail = jobMap.get(trigger.getJobKey());jobDetail.executeJob();}}public void halt(){shutDown = true;}}

至此所有的框架代码都已经完成,写个main测试下

public static void main(String[] args) {Scheduler scheduler = new Scheduler();scheduler.schedulerJob(new JobDetail(Job.class, "job01"), new Trigger(System.currentTimeMillis() + 1000));scheduler.schedulerJob(new JobDetail(Job.class, "job02"), new Trigger(System.currentTimeMillis() + 2000));scheduler.start();}

上述的设计,可以说Qz是去除安全验证和多线程同步问题编写的基本调度任务。下面来看真实案例

public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("定时器任务执行" + new Date(System.currentTimeMillis()));JobDataMap map=jobExecutionContext.getMergedJobDataMap();System.out.println("参数值"+map.get("uname"));}public static void main(String[] args) throws Exception {//1.创建Scheduler的工厂SchedulerFactory sf = new StdSchedulerFactory();//2.从工厂中获取调度器实例Scheduler scheduler = sf.getScheduler();//3.创建JobDetail(作业信息)JobDetail jb = JobBuilder.newJob(MyJob.class).withDescription("this is a test job") //job的描述.withIdentity("testJob", "testGroup") //job 的name和group.build();//向任务传递数据JobDataMap jobDataMap = jb.getJobDataMap();jobDataMap.put("uname", "张三");//任务运行的时间,SimpleSchedle类型触发器有效long time = System.currentTimeMillis() + 3 * 1000L; //3秒后启动任务Date statTime = new Date(time);//4.创建Trigger//使用SimpleScheduleBuilder或者CronScheduleBuilderTrigger t = TriggerBuilder.newTrigger().withDescription("").withIdentity("ramTrigger", "ramTriggerGroup").startAt(statTime)  //默认当前时间启动//普通计时器//.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).withRepeatCount(3))//间隔3秒,重复3次//表达式计时器.withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?")) //3秒执行一次.build();//5.注册任务和定时器scheduler.scheduleJob(jb, t);//6.启动 调度器scheduler.start();}
}

Quartz的分布式

关于分布式调度的二个核心问题:

  1. Quartz 如何向每台服务器分配资源
  2. Quartz怎么保证在一台挂机的情况下,保证任务不丢失

JobStore

Quartz将调度程序的所有的工作数据包括:Jobs,triggers,日历等信息,交由JobStore管理。JobStore的存储方式分为RAM和JDBC两种。群集模式下使用的JDBC。

下面是分析QuartzSchedulerThread源码解决Quartz 如何向每台服务器分配资源,中JobStore的主要作用函数

public interface JobStore {// 此方法主要是申请将要执行任务://  1. 从triggers表中拉取状态为 WAITING 的 Trigger//  2. Trigger状态从WAITING改为 ACQUIRED,//  3. 如果2修改成功,则向 FIRED_TRIGGERS 表插入记录// 此方法有两种方式保证任务的分配//  1. 乐观锁,即任务从WAITING改为 ACQUIRED失败,则表示被别台机子分配,也可能ABA问题引起任务重复执行//  2. 悲观锁, 步骤1前,通过Lock表进行上锁List<OperableTrigger> acquireNextTriggers(long noLaterThan, int maxCount, long timeWindow);// 此方法主要作用在Trigger的触发:// 1. 将Trigger状态ACQUIRED, 将 FIRED_TRIGGERS状态改为 EXECUTING// 2. 计算trigger的NEXT_FIRE_TIME// 3. 如果  NEXT_FIRE_TIME 为空,trigger状态 变成 STATE_COMPLETE, 并不进行4步骤// 4. 如果不允许并发执行,将 trigger状态 变成 BLOCKED, 否则 置为wait (这里就是导致上面ABA问题的主要原因)List<TriggerFiredResult> triggersFired(List<OperableTrigger> triggers);// 通过shellJob结果监听器notifyJobStoreJobComplete进行回调//  1. 如果任务正常, 则将FIRED_TRIGGERS记录删除void triggeredJobComplete(OperableTrigger trigger, JobDetail jobDetail, Trigger.CompletedExecutionInstruction triggerInstCode);
}

下面是分析ClusterManager源码解决Quartz 保证任务不丢失

  1. 项目启动时,会这 SCHEDULER_STATE 表 插入数据
  2. 之后维护和 SCHEDULER_STATE 的心跳
  3. 如果发布哪台服务器掉线,则重置任务继续执行 @see JobStoreSupport.clusterRecover

Quartz 架构

经上面分析,我们可以得出Quartz的大致结构图

主要参考

《quartz源码解析–转》
《记一次Quartz重复调度(任务重复执行)的问题排查》
《Quartz定时任务调度 》

任务调度框架quartz相关推荐

  1. quartz框架_定时任务调度框架Quartz

    最近需要写一个每天定点自动执行的定时任务,对于以前自己写小项目,可能会选择java自带的Timer类,但是对于公司中的项目,Timer类实现定时任务只能有一个后台线程执行任务,并且只能让程序按照某个频 ...

  2. Spring整合定时任务调度框架Quartz实

    Spring整合定时任务调度框架Quartz实战 定时的任务处理在程序开发中应用的相当普遍,之前一直使用JDK的Timer类库来做任务调度功能不是很方便,因为它不能像cron服务那样可以指定具体年.月 ...

  3. 任务调度框架Quartz(一) Quartz——一个强大的定时任务调度框架

    Quartz,水晶.石英,一个简单朴素有美丽的名字,在Java程序界,Quartz大名鼎鼎,很多Java应用几乎都集成或构建了一个定时任务调度系统,Quartz是一个定时任务调度框架. 何为定时任务调 ...

  4. 分布式定时任务调度框架Quartz

    文章目录 一.Quartz引言 二.Quartz使用 2.1 导入依赖 2.2 定义Job 2.3 API测试 2.3.1 细节 2.4 配置 2.5 核心类说明 三.Trigger触发器 3.1 S ...

  5. Java任务调度框架Quartz

    转自:http://blog.csdn.net/yuebinghaoyuan/article/details/9045471 介绍 Quartz is a full-featured, open so ...

  6. 一文揭秘定时任务调度框架quartz

    之前写过quartz或者引用过quartz的一些文章,有很多人给我发消息问quartz的相关问题, quartz 报错:java.lang.classNotFoundException quartz源 ...

  7. Java任务调度框架Quartz教程实例

        介绍 Quartz is a full-featured, open source job scheduling service that can be integrated with, or ...

  8. java quartz实例_Java任务调度框架Quartz教程实例

    介绍 Quartz is a full-featured, open source job scheduling service that can be integrated with, or use ...

  9. 任务调度框架Quartz用法指南(超详细)

    前言 项目中遇到一个,需要 客户自定任务启动时间 的需求.原来一直都是在项目里硬编码一些定时器,所以没有学习过. 很多开源的项目管理框架都已经做了Quartz的集成.我们居然连这么常用得东西居然没有做 ...

  10. 任务调度框架Quartz用法指南

    前言 项目中遇到一个,需要客户自定任务启动时间 的需求.以往都是在项目中直接硬编码一些定时器,趁着这次机会将quartz的相关知识记录下来. Quartz是OpenSymphony开源组织在Job s ...

最新文章

  1. 报名 | 网易MCtalk: 5G+AI新时代 探索音视频技术创新与实践
  2. vue实现表格组件,带分页
  3. Windows Azure NotificationHub+Firebase Cloud Message 实现消息推动(付源码)
  4. 对 SAP Spartacus 进行服务器端构建时,编译的资源列表
  5. org.json.JSONException: Value of type java.lang.String cannot be converted to JSONArra
  6. 解决iphone横屏时字体变大问题或者内容大小不一样等...
  7. mysql 的 null值_MySQL NULL值
  8. nowcoder-linux
  9. c语言如何输出动态数组,C语言动态数组的使用实现代码
  10. 近期购书体验:当当相对最棒,卓越蜗牛,京东缺货
  11. JAVA POI报错:org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTRImpl.getXmlObjectArray
  12. 电脑必备:通用输入法状态提示,再也不怕按错,再也不用看右下角
  13. Ubuntu16.0.4 安装rebar3指南
  14. 电脑开机就黑屏的几种原因以及解决方案
  15. cmd chcp命令切换字符格式
  16. 人工智能数学基础:利用导数判断函数单调性、凹凸性、极值、最值和描绘函数图形
  17. 我爱粟裕--与针式PKM的注册用户的QQ对话系列[2]
  18. 【转】【Grub2】UEFI添加grub2引导
  19. auto-drawing
  20. js中遍历数组加到新数组_JS几种数组遍历方式总结

热门文章

  1. 20175308 实验三《敏捷开发与XP实践》
  2. android dropbear 密码,Android 利用dropbear工具 配置ssh服务
  3. 用 Python 进行游戏开发
  4. 采用freemarker模板引擎作为Java邮件模板
  5. 蚂蚁金服ATEC人工智能大赛
  6. MD5信息摘要-文件的独一无二的“数字指纹”
  7. 常见加密方法(持续更新)
  8. 免费下载文库原格式文档![技术福利]
  9. 在电脑上不能打开phpMyAdmin:即网址http://localhost:8080/phpMyAdmin/解决方法如下----潘万丁
  10. 一家阿里巴巴批发的店主