jobDataMap能够用来装载可序列化的对象
,用于在job执行的时候获取。html
注:jobDetail
和trigger
中均可以添加jobDataMap,后面的对象会把前面对象相同键值对象的值覆盖
。java
job实体类建立代码(建立job示例,添加jobDataMap)api
public static void main(String[] args) throws SchedulerException, ParseException { SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.start(); // 定义job,绑定咱们的定时任务 JobDetail job2 = newJob(HelloJob.class) .usingJobData("name", "李四") .usingJobData("characteristic", "22") .build(); // 执行任务,用定义好的触发器 和 任务 scheduler.scheduleJob(job2, getTrigger1()); }
job类代码(job运行示例,获取jobDataMap)服务器
public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); String name = jobDataMap.get("name").toString(); String characteristic = jobDataMap.get("characteristic").toString(); JobDataMap mergedJobDataMap = context.getMergedJobDataMap(); String mergedName = mergedJobDataMap.getString("name"); System.out.println("name : " + name); System.out.println("mergedName:" + mergedName); System.out.println("characteristic : " + characteristic); }
trigger并发
/** * 触发器当即触发,而后每隔2秒 触发一次,22:55:00: */ private static SimpleTrigger getTrigger1() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); //定义一个任务触发器 return TriggerBuilder.newTrigger() .withIdentity("job2", "group2") //定点触发 //.startAt(sdf.parse("2018-09-27 10:27:00")) // 五秒钟后触发 .startAt(DateBuilder.futureDate(5, DateBuilder.IntervalUnit.SECOND)) .withSchedule( simpleSchedule() .withIntervalInSeconds(2) .repeatForever() //.withRepeatCount(0) ) .usingJobData("name",",,") //.endAt(DateBuilder.dateOf(22, 55, 0)) .build(); }
测试结果:测试
name : 李四 mergedName:,, characteristic : 22
trigger是触发器,任务什么时候运行、运行几回
,它说了算。ui
设置TriggerKey能够经过JobBuilder的.withIdentity()
进行设置,以下:默认api提供三种方式 <img src="https://ws3.sinaimg.cn/mw690/005AQjvJly1fw41dc8fvjj30s608wq4z.jpg" alt="image">this
全参数的源码以下:code
public TriggerBuilder<T> withIdentity(String name, String group) { key = new TriggerKey(name, group); return this; }
注:name属性是必填的,group不写,默认值为:default
orm
JobKey大同小异,不予介绍。
使用场景:在一个指定时间段内执行一次做业任务
或是在指定的时间间隔内屡次执行做业任务
,SimpleTrigger应该能知足你的调度需求。
例如:
private static SimpleTrigger getTrigger2() throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); //定义一个任务触发器 return newTrigger() .withIdentity("job1", "group1") //定点触发 .startAt(sdf.parse("2018-09-27 10:27:00")) .withSchedule(simpleSchedule() .withIntervalInSeconds(2) .withRepeatCount(0) ).build(); }
注:startAt中的日期可使用DateBuilder,示例,在指定时间延迟5秒执行
.startAt(DateBuilder.futureDate(5, DateBuilder.IntervalUnit.SECOND))
执行常量以下:
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY MISFIRE_INSTRUCTION_FIRE_NOW MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
触发指令设置
withMisfireHandlingInstructionFireNow ——以当前时间为触发频率当即触发执行 ——执行至FinalTIme的剩余周期次数 ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算获得 ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值 withMisfireHandlingInstructionIgnoreMisfires ——以错过的第一个频率时间马上开始执行 ——重作错过的全部频率周期 ——当下一次触发频率发生时间大于当前时间之后,按照Interval的依次执行剩下的频率 ——共执行RepeatCount+1次 withMisfireHandlingInstructionNextWithExistingCount ——不触发当即执行 ——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数 ——以startTime为基准计算周期频率,并获得FinalTime ——即便中间出现pause,resume之后保持FinalTime时间不变 withMisfireHandlingInstructionNowWithExistingCount ——以当前时间为触发频率当即触发执行 ——执行至FinalTIme的剩余周期次数 ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算获得 ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值 withMisfireHandlingInstructionNextWithRemainingCount ——不触发当即执行 ——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数 ——以startTime为基准计算周期频率,并获得FinalTime ——即便中间出现pause,resume之后保持FinalTime时间不变 withMisfireHandlingInstructionNowWithRemainingCount ——以当前时间为触发频率当即触发执行 ——执行至FinalTIme的剩余周期次数 ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算获得 ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值 MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT ——此指令致使trigger忘记原始设置的starttime和repeat-count ——触发器的repeat-count将被设置为剩余的次数 ——这样会致使后面没法得到原始设定的starttime和repeat-count值
使用场景:CronTrigger比SimpleTrigger更经常使用,当你须要一个基于日历般概念的做业调度器,而不是像SimpleTrigger那样精确指定间隔时间。
使用cronTrigger,你能够这样指定触发时间表例如每周五的中午
,或是每周末的上午9:30
,甚至是一月份每周1、3、五上午9:00到10:00之间每5分钟
。
CronTrigger也须要指定startTime让调度器生效,指定endTime让调度器终止。
Cron表达式其实是由7个子表达式组成的字符串,这些子表达式用空格隔开,分别表明:
类型 | 范围 |
---|---|
秒 | 0-60 |
分 | 0-60 |
小时 | 0-23 |
月份中的天数 | 0-31,但须要注意,有些月份如没有31 |
月 | 0-11,可使用:JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC |
星期中的天数 | 1-7,可使用: SUN,MON,TUE,WED,THU,FRI,SAT |
年(可选) | 通常不用 |
/ : - 若是你在分钟字段写“0/15”,这表示“每次从一小时中的第0分钟开始,每隔15分钟触发”, - 若是你在分钟字段上写“3/20”,这表示“每次从一小时中的第3分钟开始,每隔20分钟触发”——换句话说,这跟在分钟字段上指定“3,23,43”是同样的。
? : - 字符容许出如今月份中的天数和星期中的天数字段中。它通常用来指定“不关心的值”。 - 当你须要在这两个字段中的一个指定不肯定的值是很是方便的,这个字符不能用在其余的字段中。
L : - 字符容许出如今月份中的天数和星期中的天数字段中 - “L”字符出如今月份中的天数字段中表示“每个月的最后一天”——1月31日,平年的2月28日
w : - 字符用来指定给定日期的最近一个工做日(工做日指的是从周一到周五) - 若是你在月份中的天数字段的值指定为“15w”,这表示“离每个月15号最近的工做日”。
'井' : - ”字符用来指定每个月的第N个工做日 - 星期中的天数字段的值为“6#3”或是“FRI#3”表示“每个月的第三个星期五”。
Cron案例1——仅仅表示每隔5分钟触发一次:"0 0/5 * * * ?"
Cron案例2——表示每隔5分钟,在过了10秒后触发一次(例如上午10:00:10,10:05:10等):"10 0/5 * * * ?"
Cron案例3——表示每一个周三到周五,在上午10:30,11:30,12:30和13:30分触发:"0 30 10-13 ? * WED,FRI"
Cron案例4——表示每个月从5号到20号,上午8时到10时之间的每半小时触发,注意这个触发器只在8:00,8:30,9:00和9:30分触发,上午10:00不会触发:"0 0/30 8-9 5,20 * ?"
注意有些调度需求因太复杂例如“上午9:00到10:00之间的每5分钟,下午1:00到10:00的每20分钟”,而不能用单一的触发器来表示。这种状况的解决方案是建立两个简单的触发器,将它们注册到调度器中去运行同一个做业任务。
触发器,天天从的下午3:33 触发一次
private static CronTrigger getTrigger5() throws ParseException { //定义一个任务触发器 return newTrigger() .withIdentity("job1", "group1") .withSchedule(CronScheduleBuilder.cronSchedule("0 27 16 * * ?")) //或者下边这样写 // .withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(15, 33)) .forJob("job1", "group1") .build(); }
注:CronScheduleBuilder默认提供了一些经常使用表达式实现,以下图,请自行尝试
<img src="https://ws2.sinaimg.cn/mw690/005AQjvJly1fw440fu2jnj31dw0fowkp.jpg" alt="image">
CronTrigger的触发失败指令常量:
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY MISFIRE_INSTRUCTION_DO_NOTHING MISFIRE_INSTRUCTION_FIRE_NOW
触发指令设置:
withMisfireHandlingInstructionDoNothing ——不触发当即执行 ——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行 withMisfireHandlingInstructionIgnoreMisfires ——以错过的第一个频率时间马上开始执行 ——重作错过的全部频率周期后 ——当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行 withMisfireHandlingInstructionFireAndProceed ——以当前时间为触发频率马上触发一次执行 ——而后按照Cron频率依次执行
补全问题
问题介绍: - 1).执行暂停任务,重启后,在暂停期间没执行的任务又TM给补上了 - 2).服务器挂了,重启后,在暂停期间没执行的任务又TM给补上了
解决方式:
cronSchedule(cronExpression).withMisfireHandlingInstructionFireAndProceed() 或者 cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing()
设置完成从新启动发现没软用
#这个时间大于10000(10秒)会致使MISFIRE_INSTRUCTION_DO_NOTHING不起做用。 org.quartz.jobStore.misfireThreshold = 5000
解释:
misfireThreshold表示实际执行的时间与下一次应该执行时间之间的差值,超过这个差值就不会执行,低于这个差值就会执行。 好比我每3秒执行一次,misfireThreshold=6000,当你暂停低于6秒内,它会弥补执行,超过6秒,它就再也不弥补执行了。
(quartz暂停及恢复任务解决恢复时一咕噜把未执行的全补回来的问题)[http://www.itboth.com/d/mqE3In/quartz-java]<br> (quartz 失败触发指令)[http://www.voidcn.com/article/p-yvvrqdrt-ku.html]<br>