在上一篇文章中,我们讲完了核心组件,原理概述,以及Job和这两个组件的详解。
现在继续往下:
如前所述,最常用的两种是:和
无论哪种方式,他们都有一些共同点
所有类型都有这个属性,代表身份; 除此之外,还有很多其他的共同属性。 这些属性可以在构建时设置。
的公共属性是:
优先事项()
如果你有很多(或者线程池中的线程太少),可能没有足够的资源同时触发所有的; 在这种情况下,您可能希望控制首先使用哪些工作线程。 为此,您可以在属性上进行设置。 比如你有N个线程需要同时触发,但是只有Z个线程,那么优先级最高的会先触发。 如果没有设置优先级,则使用默认优先级,值为5; 属性的值可以是任何整数,正数或负数。
注意:只有同时触发的才会比较优先级。 10:59 触发的总是在 11:00 触发的之前执行。
注意:如果是可恢复的,恢复后调度的时候,优先级和原来的一样。
失误()
还有一个重要的属性; 如果关闭了,或者线程池中没有可用的线程来执行作业,那么持久化的就会错过(miss)它的触发时间,也就是错过()。 不同的类型有不同的机制。 它们都默认使用“智能机制(smart)”,即根据类型和配置动态调整行为。 启动时,查询所有错过()的持久化。 然后根据各自的机制更新信息。 当您在项目中使用它时,您应该熟悉各种类型的机制,这些机制在 . 具体的机制会在具体的时候介绍。
日历示例()
对象(不是 java.util.)可以在定义和存储时关联。 用于从 的时间表中排除时间段。 例如,您可以创建一个在每个工作日上午 9:30 执行的一个,然后添加一个以排除所有商业假期。
任何实现该接口的可序列化对象都可以用作对象。 界面如下:
package org.quartz;
public interface Calendar {
public boolean isTimeIncluded(long timeStamp);
public long getNextIncludedTime(long timeStamp);
}
请注意,这些方法的参数类型很长。 正如您可能猜到的那样,它们是以毫秒为单位的时间戳。 即排除周期的单位可以精确到毫秒。 您可能对“排除一整天”比较感兴趣。 提供的 org..impl。 类可以很容易地实现。
必须先实例化,然后用()方法注册。 如果使用,在实例化后,需要调用(Date date)方法将时间段排除在日程表之外。 以下示例对多个实例使用相同的实例:
public class CornTest {
public static void main(String[] args) throws SchedulerException {
// 创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 创建要排除的时间
HolidayCalendar holidayCalendar = new HolidayCalendar();
holidayCalendar.addExcludedDate(new Date());
scheduler.addCalendar("hhh", holidayCalendar,false,false);
// 创建任务实例
JobDetail jobDetailA = JobBuilder.newJob(MyJob.class)
.requestRecovery(false)
.storeDurably(false)
.withIdentity("helloA", "job")
.usingJobData("xpA","好帅好帅")
.build();
// 创建触发器
CronTrigger triggerA = TriggerBuilder.newTrigger()
.withIdentity("triggerA", "trigger")
.startNow()
// 每2秒执行一次
.withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?"))
.modifiedByCalendar("hhh")
// 8s后结束
.endAt(new Date(System.currentTimeMillis() + 8000))
.build();
// 调度器接管任务和触发器
scheduler.scheduleJob(jobDetailA, triggerA);
// 开始执行
scheduler.start();
}
}
#
可用于:在指定时间执行一次,从某个时间开始按一定时间间隔执行多次。
比如你可以设置一个在2022年4月28日晚上8点15分执行,或者在这个时间点每两分钟执行一次,重复5次。
属性包括:开始时间、结束时间、重复次数、重复间隔
唯一需要注意的是结束时间可能会影响重复次数。 有可能在重复次数达到设定值之前就到了结束时间。
通过r设置主要属性和相关属性来设置实例。
看下面的例子:从当前时间开始,每5s执行一次,重复两次
public class TestScheduler {
public static void main(String[] args) throws SchedulerException {
// 创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 创建任务实例
JobDetail jobDetailA = JobBuilder.newJob(MyJob.class)
.requestRecovery(false)
.storeDurably(false)
.withIdentity("helloA", "job")
.usingJobData("xpA","好帅好帅")
.build();
// 创建触发器
SimpleTrigger triggerA = TriggerBuilder.newTrigger()
.withIdentity("triggerA", "trigger")
.startNow()
// 每五秒执行一次,重复两次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5).withRepeatCount(2))
.build();
// 调度器接管任务和触发器
scheduler.scheduleJob(jobDetailA, triggerA);
// 开始执行
scheduler.start();
}
}
你可以看到结果:
一共处死三人!
这是因为执行开始(即())不计入重复次数
我们再做一个测试,根据上面的要求加上一个结束时间:8秒结束:
SimpleTrigger triggerA = TriggerBuilder.newTrigger()
.withIdentity("triggerA", "trigger")
.startNow()
// 每五秒执行一次,重复两次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5).withRepeatCount(2))
// 8s后结束
.endAt(new Date(System.currentTimeMillis() + 8000))
.build();
这次的结果是只执行了两次:
因为来不及重复第二次,就结束了。
(和其他人)将为未明确设置的属性选择合理的默认值。 例如:如果不调用(...)方法,会生成一个随机名称; 如果不调用(...)方法,默认使用当前时间,立即生效。
##策略(错过触发)
有几个相关的策略会告诉您在发生这种情况时该怎么做。
以下是未命中触发策略常量:
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
配置的时候可以选择er中使用哪种策略
默认使用智能策略(smart),根据实例的配置和状态,在所有策略中动态选择一个策略。
通常比 .
你知道玉米表情吗~
尽管如此,与 一样,有一个指定何时生效,还有一个(可选)指定何时停止计划。
cron 表达式
cron表达式介绍:
cron 表达式是由 5 或 6 个空格分隔并分为 6 或 7 个域的字符串。 每个域代表一种含义。 Cron 有以下两种语法格式:
(1) 小时 月 年
(2) 小时月
一、结构
玉米从左到右(以空格分隔):秒、分、时、月、日、月、周、日、年
2.各字段的含义
字段允许值允许的特殊字符
第二()
0~59的整数
, - * / 四个字符
观点()
0~59的整数
, - * / 四个字符
小时
从 0 到 23 的整数
, - * / 四个字符
日期()
从 1 到 31 的整数(但您需要考虑您所在月份的天数)
,- * ? /LWC 八字
月
从 1 到 12 的整数或 JAN-DEC
, - * / 四个字符
星期()
从 1 到 7 的整数或 SUN-SAT (1=SUN)
, - * ? /LC#八个字符
年份(可选,留空)(年份)
1970~2099
, - * / 四个字符
防范措施:
每个字段都使用数字,但也可以出现以下特殊字符,它们的含义是:
(1) * :表示匹配该字段的任意值。 如果该字段中使用*,则表示该事件将每分钟触发一次。
(2) ?:只能在和两个域中使用。 它也匹配域的任何值,但它不匹配。 因为和会互相影响。 比如你想在每个月的20号触发调度,不管20号是星期几,你只能用13 13 15 20 * ?,其中最后一位只能用? ,而不是用*,如果用*表示无论星期几都会触发,就不是这样了。
(3)-:表示范围。比如在字段中使用5-20,表示从5分钟到20分钟每分钟触发一次
(4)/:表示从开始时间开始触发,以后每隔固定时间触发。 例如域中使用5/20表示每5分钟触发一次,而25、45等分别触发一次。
(5),: 表示列出枚举值。 例如:在字段中使用5,20,表示每分钟在5和20分钟触发。
(6) L:表示最后一个,只能出现在和字段中。 如果字段中使用5L,则表示将在最后一个星期四触发。
(7) W:表示有效工作日(周一至周五),只能出现在字段中,系统会在距离指定日期最近的有效工作日触发事件。 例如:使用5W时,如果5号是星期六,则在最近的工作日:星期五,即4号触发。 如果5号是周日,则在6号(周一)触发; 如果5号是周一到周五的某一天,则在5号触发。 还有一点,W 的最近一次查找不会跨越数月。
(8)LW:这两个字可以并用,表示某月的最后一个工作日,即最后一个星期五。
(9)#:用于确定每个月的星期几,只能出现在字段中。 例如4#2,表示某月的第二个星期三。
3.常用表达示例
(0) 0/20 * * * * ? 表示任务每20秒触发一次
(1) 0 0 2 1 * ? 表示每月1号凌晨2点调整任务
(2) 0 15 10 ? * MON-FRI表示job在周一到周五每天早上10:15执行
(3) 0 15 10 ? 6L 2002-2006 表示该操作在2002-2006每个月的最后一个周五上午10点15分执行
(4) 0 0 10,14,16 * * ? 每天上午 10 点、下午 2 点、下午 4 点
(5) 0 0/30 9-17 * * ? 朝九晚五的工作时间每半小时
(6) 0 0 12 ? * WED 指每周三中午 12 点
(7) 0 0 12 * * ? 每天中午12点触发
(8) 0 15 10 ? * * 每天上午 10:15 触发
(9) 0 15 10 * * ? 每天上午10点15分触发
(10) 0 15 10 * * ? * 每天上午10:15触发
(11) 0 15 10 * * ? 2005 2005年每天上午10点15分触发
(12) 0 * 14 * * ? 每天下午 2 点到 2 点 59 分每 1 分钟触发一次
(13) 0 0/5 14 * * ? 每天下午 2 点到 2:55 之间每 5 分钟触发一次
(14) 0 0/5 14,18 * * ? 每天下午 2 点到 2 点 55 分和下午 6 点到 6 点 55 分之间每 5 分钟触发一次
(15) 0 0-5 14 * * ? 每天下午2点到2点05分每1分钟触发一次
(16) 0 10,44 14 ? 3 WED 在每年三月的周三下午 2:10 和 2:44 触发
(17) 0 15 10 ? * MON-FRI 周一至周五上午 10:15 触发
(18) 0 15 10 15 * ? 每月15日上午10点15分触发
(19) 0 15 10 L* ? 每月最后一天上午 10:15 触发
(20) 0 15 10 ? * 6L 每月最后一个周五上午10:15触发
(21) 0 15 10 ? * 6L 在2月至2005年每个月的最后一个星期五上午10:15触发
(22) 0 15 10 ? * 6#3 在每个月的第三个星期五上午 10:15 触发
笔记:
(1) 一些子表达式可以包含范围或列表
例如:子表达式(day(week))可以是"MON-FRI", "MON, WED, FRI", "MON-WED, SAT"
“*”字符代表所有可能的值
因此,“”代表子表达式(month)中每个月的含义,“”代表子表达式(day(week))中星期几的含义
“/”字符用于指定值的增量
例如:子表达式()中的“0/15”表示从第0分钟开始,每15分钟
()子表达式中的“3/20”表示从第3分钟开始,每20分钟一次(与“3、23、43”意义相同)
这 ”?” 只用在day(month)和day(week)这两个子表达式中,表示没有指定值
当两个子表达式中的一个被赋值时,为了避免冲突,需要将另一个子表达式的值设置为“?”
“L”字符只用在日(月)和日(周)子表达式中,是单词“last”的缩写
但是它在两个子表达式中的含义是不同的。
在日(月)子表达式中,“L”表示该月的最后一天
在日(周)自我表达中,“L”表示一周的最后一天,也就是SAT
如果“L”前面有特定的东西,它有其他含义
例如:“6L”表示本月的最后6日,“FRIL”表示本月的最后一个星期五
注意:使用“L”参数时,不要指定列表或范围,因为这会导致问题
例子:
只需要稍作改动:
// 创建触发器
CronTrigger triggerA = TriggerBuilder.newTrigger()
.withIdentity("triggerA", "trigger")
.startNow()
// 每2秒执行一次
.withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?"))
// 8s后结束
.endAt(new Date(System.currentTimeMillis() + 8000))
.build();
执行3次没有问题
阐明
错过的触发策略常量为
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_DO_NOTHING
MISFIRE_INSTRUCTION_FIRE_NOW
与错过触发不同,默认的智能策略(smart)被解释为立即触发。
您还可以在创建时指定一个错过的触发策略: