最近需要写一个每天定点自动执行的定时任务,对于以前自己写小项目,可能会选择java自带的Timer类,但是对于公司中的项目,Timer类实现定时任务只能有一个后台线程执行任务,并且只能让程序按照某个频度执行,并不能在指定时间点执行。同时由于一般大型项目会有多个job分别需要在不同的时间点自动执行,单线程的Timer满足不了需求。而任务调度框架Quartz刚好满足这些需求,我是实习公司的项目中就已经配置好了这个框架,在使用的时候了解了这个quartz,现总结如下。
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能: 持久性作业 - 就是保持调度定时的状态; 作业管理 - 对调度作业进行有效的管理; 复制代码
quartz主要包括三个部分的模块,定时任务Job、触发器Trigger、调度器Scheduler。
简单的流程就是:调度器根据触发器来执行任务。
//预定义Job接口--pom.xml需要加载依赖的包 public interface Job { void execute(JobExecutionContext var1) throws JobExecutionException; } //任务逻辑通过实现Job接口,并且重写execute方法,将需要执行的逻辑实现写在execute函数中 public class TestJob implements Job { /**把要执行的操作,写在execute方法中 */ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); System.out.println("I can do something..."); System.out.println(sdf.format(new Date())); } } 参考:https://juejin.im/post/5a0c08c5f265da4335624c8f //1. 创建一个JodDetail实例 将该实例与Hello job class绑定 (链式写法) JobDetail jobDetail = JobBuilder.newJob(QuartzOrderReturn.class)// 定义Job类为QuartzOrderReturn类,这是真正的执行逻辑所在 .withIdentity(StrUtils.uuid()) .setJobData(jobDataMap) .build(); 复制代码
//创建SimpleTrigger startTime end 分别表示触发器的首次触发时间和不再被触发的时间 SimpleTrigger trigger = newTrigger() .withIdentity("trigger", "group") .startAt(startTime) .endAt(end) .withSchedule( simpleSchedule().withIntervalInHours( executeFrequency).withRepeatCount( executeBatch)).build(); 复制代码
CronTrigger 可以配置更复杂的触发时刻表,基于日历的作业触发器。使用SimpleTrigger触发器需要设置不同的属性支撑,代码编写比较多,并且不灵活。而CornTrigger就比较灵活,可以通过设计Corn表达式来控制复杂的触发时间表。
Corn表达式:用于配置CornTrigger实例,由7个表达式组成的字符串,描述了时间表的详细信息。
//创建CornTrigger 比如下面的就是设计每天中午十二点整触发 CronTrigger trigger = newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule("0 0 12 * * ?")).build(); // 把job和trigger加入调度 scheduler.scheduleJob(jobDetail, trigger); //启动scheduler scheduler.start(); 复制代码
对于Corn的理解参考: mp.weixin.qq.com/s/-0kwxC2lz… ?
在线生成Corn表达式: cron.qqe2.com/// 把job和trigger加入调度 scheduler.scheduleJob(jobDetail, trigger); //启动scheduler scheduler.start(); 复制代码
//一个完整的实例 private void quartzOrderReturn(List<String> returnIds) { try { Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("returnIds", returnIds); //1. 创建一个JodDetail实例 将该实例与Hello job class绑定 (链式写法) JobDetail jobDetail = JobBuilder.newJob(QuartzOrderReturn.class)// 定义Job类为QuartzOrderReturn类,这是真正的执行逻辑所在 .withIdentity(StrUtils.uuid()) .setJobData(jobDataMap) .build(); // 2. 定义一个Trigger,定义该job在10秒后执行,并且执行一次 Date startTime = new Date(); startTime.setTime(startTime.getTime() + 10000L); SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(StrUtils.uuid(), HeaderNameConstants.getQuartzTrigger()).startNow()// 定义名字和组 .startAt(startTime) .withSchedule(SimpleScheduleBuilder .simpleSchedule() .withIntervalInSeconds(2)//定义时间间隔是2秒 .withRepeatCount(0)//定义重复执行次数是无限次 ) .build(); // 4. 将trigger和jobdetail加入这个调度 scheduler.scheduleJob(jobDetail, trigger); // 5. 启动scheduler scheduler.start(); // 6. 任务执行后20秒后休眠 Thread.sleep(startTime.getTime() + 20000L); // 7. 如果定时任务开启则关闭 if (scheduler.isStarted()) { scheduler.shutdown(true); } } catch (SchedulerException | InterruptedException e) { e.printStackTrace(); } } 复制代码
//每个2秒执行一次 string cronParam = "*/2 * * * * ?"; //创建计划任务抽象工厂 ISchedulerFactory sf = new StdSchedulerFactory(); //创建计划任务 IScheduler sched = sf.GetScheduler(); //创建job JobDetail job = new JobDetail("myJob","group", typeof(MyJob)); //创建触发器 Trigger trigger = new CronTrigger("myTrigger","group",cronParam); //将job和trigger注入到计划任务中 sched.ScheduleJob(job, trigger); //启动计划任务 sched.Start(); //关闭计划任务 //sched.Shutdown(); 复制代码参考: www.cnblogs.com/wangjiming/…
定时一般是使用时间轮(time wheel)算法实现。 时间轮算法简单来说可以用下图表示,其主体是一个循环列表,
新任务加入时,会根据目前指针所在位置和需要等待的时间,确定保存在时钟的哪个位置。时间轮有3个重要的属性参数,ticksPerWheel(一轮的tick数),tickDuration(一个tick的持续时间)以及 timeUnit(时间单位)。
例如 当ticksPerWheel=60,tickDuration=1,timeUnit=秒,这就和现实中秒针走动完全类似了,我们就用这种情况举例子。箭头运行到一个位置时,就运行相应的任务,然后通过sleep将时间补足一秒,正好就开始下一个tick了。这样循环往复,就可以让每个任务在需要的时间执行。
参考链接: www.zhihu.com/question/41… www.kafka.cc/archives/24…