JobKey、TriggerKey、Trigger、priority、misfire 、calendar调度使用

目录

一:JobKey与TriggerKey

二:Trigger

三:优先级(priority)

四:错过触发(misfire Instructions)

五:日历(calendar)

5.1AnnualCalendar

5.2HolidayCalendar

5.4WeeklyCalendar

5.5DailyCalendar

5.6CronCalendar

5.7组合日历


一:JobKey与TriggerKey

JobKey是表明Job身份的一个对象,里面封装了Job的name和group,TriggerKey同理。
之前我们在构建JobDetail和Trigger是用的是以下方法来指定他们对于的name和group
JobBuilder里面

 public JobBuilder withIdentity(String name, String group) {
        key = new JobKey(name, group);
        return this;
    }

TriggerBuilder里面

 public TriggerBuilder<T> withIdentity(String name, String group) {
        key = new TriggerKey(name, group);
        return this;
    }

关于withIdentity方法,我们可以直接构造一个TriggerKey或者JobKey,然后通过withIdentity传递给对于的Builder
在TriggerKey和JobKey中分别封装了两个静态方法来获取TriggerKey和JobKey

 

 

当我们不指定group时,Quartz会用默认的组名DEFAULT

二:Trigger

所有类型的trigger都有TriggerKey这个属性,表示trigger的身份;除此之外,trigger还有很多其它的公共属性。这些属性,在构建trigger的时候可以通过TriggerBuilder设置。
我们可以通过查看TriggerBuilder里面的一些方法跟Trigger的源码来了解到这些属性。
如下:
 

public class TriggerBuilder<T extends Trigger> {

    private TriggerKey key;
    private String description;
    private Date startTime = new Date();
    private Date endTime;
    private int priority = Trigger.DEFAULT_PRIORITY;
    private String calendarName;
    private JobKey jobKey;
    private JobDataMap jobDataMap = new JobDataMap();
    
    private ScheduleBuilder<?> scheduleBuilder = null;
    
    private TriggerBuilder() {
        
    }
   .........
  }
public abstract class AbstractTrigger<T extends Trigger> implements OperableTrigger {

    private static final long serialVersionUID = -3904243490805975570L;

    /*
    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    *
    * Data members.
    *
    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    */

    private String name;

    private String group = Scheduler.DEFAULT_GROUP;

    private String jobName;

    private String jobGroup = Scheduler.DEFAULT_GROUP;

    private String description;

    private JobDataMap jobDataMap;

    @SuppressWarnings("unused")
    private boolean volatility = false; // still here for serialization backward compatibility

    private String calendarName = null;

    private String fireInstanceId = null;

    private int misfireInstruction = MISFIRE_INSTRUCTION_SMART_POLICY;

    private int priority = DEFAULT_PRIORITY;

    private transient TriggerKey key = null;
    
}

其中比较常用的公共属性有

 1.jobKey属性:当trigger触发时被执行的job的身份;

2.startTime属性:设置trigger第一次触发的时间;该属性的值是java.util.Date类型,表示某个指定的时间点;有些类型的trigger,会在设置的startTime时立即触发,有些类型的trigger,表示其触发是在startTime之后开始生效。比如,现在是1月份,你设置了一个trigger–“在每个月的第5天执行”,然后你将startTime属性设置为4月1号,则该trigger第一次触发会是在几个月以后了(即4月5号)。

3.endTime属性:表示trigger失效的时间点。比如,”每月第5天执行”的trigger,如果其endTime是7月1号,则其最后一次执行时间是6月5号。

除了以上比较常用的属性,Trigger还有优先级(priority)、错过触发(misfire Instructions)和日历示例(calendar)这三个比较重要的属性

三:优先级(priority)

如果你的trigger很多(或者Quartz线程池的工作线程太少),Quartz可能没有足够的资源同时触发所有的trigger;这种情况下,你可能希望控制哪些trigger优先使用Quartz的工作线程,要达到该目的,可以在trigger上设置priority属性。比如,你有N个trigger需要同时触发,但只有Z个工作线程,优先级最高的Z个trigger会被首先触发。如果没有为trigger设置优先级,trigger使用默认优先级,值为5;priority属性的值可以是任意整数,正数、负数都可以。
注意:只有同时触发的trigger之间才会比较优先级。10:59触发的trigger总是在11:00触发的trigger之前执行。
注意:如果trigger是可恢复的,在恢复后再调度时,优先级与原trigger是一样的。

在构造Trigger,通过TriggerBuilder的withPriority方法来设置
 

 public TriggerBuilder<T> withPriority(int triggerPriority) {
        this.priority = triggerPriority;
        return this;
    }

四:错过触发(misfire Instructions)

如果scheduler关闭了,或者Quartz线程池中没有可用的线程来执行job,此时持久性的trigger就会错过(miss)其触发时间,即错过触发(misfire)。
当下次调度器启动或者有可以线程时,会检查处于misfire状态的Trigger。而misfire的状态值决定了调度器如何处理这个Trigger。
不同类型的trigger,有不同的misfire机制。它们默认都使用“智能机制(smart policy)”,即根据trigger的类型和配置动态调整行为。
具体的misfire机制在学习具体的trigger时再详细整理一下
 

五:日历(calendar)

Quartz的Calendar对象(不是java.util.Calendar对象)可以在定义和存储trigger的时候与trigger进行关联。
Calendar用于从trigger的调度计划中排除时间段。比如,可以创建一个trigger,每个工作日的上午9:30执行,然后增加一个Calendar,排除掉所有的商业节日。
Calendar排除时间段的单位可以精确到毫秒,同时Quartz提供了很多开箱即用的实现来满足我们的不同需求,如下
 

类名用法
org.quartz.impl.calendar.HolidayCalendar指定特定的日期,比如20140613 精度到天
org.quartz.impl.calendar.AnnualCalendar指定每年的哪一天,精度是天
org.quartz.impl.calendar.MonthlyCalendar指定每月的几号,可选值为1-31,精度是天
org.quartz.impl.calendar.WeeklyCalendar指定每星期的星期几,可选值比如为java.util.Calendar.SUNDAY,精度是天
org.quartz.impl.calendar.DailyCalendar指定每天的时间段(rangeStartingTime, rangeEndingTime),格式是HH:MM[:SS[:mmm]],也就是最大精度可以到毫秒
org.quartz.impl.calendar.CronCalendar指定Cron表达式,精度取决于Cron表达式,也就是最大精度可以到秒

注意,所有的Calendar既可以是排除,也可以是包含

HolidayCalendar与AnnualCalendar的区别

所以通常情况下,比如我想排除每年的5月1日,用AnnualCalendar就比较方便,若用HolidayCalendar,就需要注册多个HolidayCalendar到Scheduler中。

5.1AnnualCalendar

创建与注册

	// 构建SchedulerFactory实例
	SchedulerFactory schedFact = new StdSchedulerFactory();
	// 获取Scheduler实例
	Scheduler scheduler = schedFact.getScheduler();
	//创建AnnualCalendar对象
	AnnualCalendar annualday = new AnnualCalendar();
	Calendar laborDay = GregorianCalendar.getInstance();
	//设置5月1日,这里需要注意在Calendar月份的基础上+1才是真实的月份
	laborDay.set(Calendar.MONTH, Calendar.MAY+1);
	laborDay.set(Calendar.DATE, 1);
	// 排除每年5月1日,true为排除,false为包含
	annualday .setDayExcluded(laborDay, true);
	// 向Scheduler注册日历
	scheduler.addCalendar("annualday", annualday, true, true);

需要注意一下几点:

1.AnnualCalendar就算设置了年,也不会生效,它会在每一年都生效,具体逻辑可以查看源码

2.AnnualCalendar .setDayExcluded(java.util.Calendar day, boolean exclude)方法中的exclude是用来决定是包含还是排除

3.setDayExcluded有一个重载的方法,可以传入一个ArrayList<java.util.Calendar>,一次性加入多个java.util.Calendar,但是该方法默认exclude为true,就是默认是排除

4.Scheduler.addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)方法中的参数

5.replace表示是否覆盖之前设置的相同名称的Calendar ,若为false,当add相同名称的Calendar 时,会抛SchedulerException

6.updateTriggers表示若已存在的triggers已经引用 了相同名称的Calendar,是否更新triggers绑定的Calendar

绑定Trigger

SimpleTrigger triggerB = TriggerBuilder.newTrigger()
				                               .withIdentity("helloTriggerB", "helloB")
				                               .startNow()
				                               .withSchedule(SimpleScheduleBuilder
				                               .simpleSchedule()
				                               .withIntervalInSeconds(5).repeatForever())
				                               //指定trigger使用Calendar
				                               .modifiedByCalendar("annualday")
				                               .build();

5.2HolidayCalendar

该日历与AnnualCalendar差不多,区别就是设置的year是有效的,如果你希望在未来5年内都排除5月1日这一天,你需要添加5个日期,分别是 2019-5-1,2020-5-1,2021-5-1,2022-5-1,2023-5-1

		// 构建SchedulerFactory实例
		SchedulerFactory schedFact = new StdSchedulerFactory();
		// 获取Scheduler实例
		Scheduler scheduler = schedFact.getScheduler();
		//创建HolidayCalendar对象
		HolidayCalendar holidays = new HolidayCalendar();
		Calendar laborDay1 = new GregorianCalendar(2019, 5, 1);
		Calendar laborDay2 = new GregorianCalendar(2020, 5, 1);
		Calendar laborDay3 = new GregorianCalendar(2021, 5, 1);
		Calendar laborDay4 = new GregorianCalendar(2022, 5, 1);
		Calendar laborDay5 = new GregorianCalendar(2023, 5, 1);
		
		holidays.addExcludedDate(laborDay1.getTime());
		holidays.addExcludedDate(laborDay2.getTime());
		holidays.addExcludedDate(laborDay3.getTime());
		holidays.addExcludedDate(laborDay4.getTime());
		holidays.addExcludedDate(laborDay5.getTime());
		// 向Scheduler注册日历
		scheduler.addCalendar("holidays", holidays, true, true);

需要注意的是

    • HolidayCalendar考虑的是年,需要指定确定的年月日
    • AnnualCalendar是指每一年的哪一天。

    月日历,你可以定义一个月当中的若干天不触发。比如我想排除每个月的2,4,5号不触发

    		MonthlyCalendar monthlyCalendar = new MonthlyCalendar();
    		monthlyCalendar.setDayExcluded(2, true);
    		monthlyCalendar.setDayExcluded(4, true);
    		monthlyCalendar.setDayExcluded(6, true);
    		// 向Scheduler注册日历
    		scheduler.addCalendar("monthlyCalendar", monthlyCalendar, true, true);
    

    5.4WeeklyCalendar

    星期日历,可以定义每周内周几不触发。例如设置每周四不触发

    		WeeklyCalendar weeklyCalendar = new WeeklyCalendar();
    		weeklyCalendar.setDayExcluded(Calendar.THURSDAY, true);
    		// 向Scheduler注册日历
    		scheduler.addCalendar("weeklyCalendar", weeklyCalendar, true, true);
    

    需要注意的是

    1.当我们定义了WeeklyCalendar ,周六和周日就默认被排除了,如果想要不排除,需要自己把这两天通过setDayExcluded设置为false,即不排除。可以查看如下源码

     public WeeklyCalendar() {
        this(null, null);
    }
    public WeeklyCalendar(Calendar baseCalendar, TimeZone timeZone) {
        super(baseCalendar, timeZone);
    	//默认排除周六和周日
        excludeDays[java.util.Calendar.SUNDAY] = true;
        excludeDays[java.util.Calendar.SATURDAY] = true;
        excludeAll = areAllDaysExcluded();
    }
    

    2.WeeklyCalendar .setDayExcluded(int wday, boolean exclude)中的参数务必用java.util.Calendar中的定义的常量,因为国际上一周的开始第一天是周日,可以查看java.util.Calendar中定义的周常量,是从SUNDAY(1)开始的。
     

    5.5DailyCalendar

    时间范围日历,定义一个时间范围,可以让触发器在这个时间范围内触发,或者在这个时间范围内不触发,每一个DailyCalendar的实例只能设置一次时间范围,并且这个时间范围不能超过一天的边界。
    例如我要排除每天当中晚上20点到21点

    		// 构建SchedulerFactory实例
    		SchedulerFactory schedFact = new StdSchedulerFactory();
    		// 获取Scheduler实例
    		Scheduler scheduler = schedFact.getScheduler();
    		
    		Calendar start = GregorianCalendar.getInstance();
    		start.setTime(DateBuilder.dateOf(20, 0, 0));
    		
    		Calendar end = GregorianCalendar.getInstance();
    		end.setTime(DateBuilder.dateOf(21, 0, 0));
    		
    		DailyCalendar dailyCalendar = new DailyCalendar(start, end);
    		dailyCalendar.setInvertTimeRange(false);
    		// 向Scheduler注册日历
    		scheduler.addCalendar("dailyCalendar", dailyCalendar, true, true);
    

    需要注意的是

    Cron表达式日历,可以写一个表达式来排除一个时间范围,比如可以设置为排除所有的时间,但是工作时间除外,也就是 在早8点-晚5点触发,其他时间暂停。

    		// 构建SchedulerFactory实例
    		SchedulerFactory schedFact = new StdSchedulerFactory();
    		// 获取Scheduler实例
    		Scheduler scheduler = schedFact.getScheduler();
    		try {
    			CronCalendar cronCalendar= new CronCalendar("* * 0-7,18-23 ? * *");
    			// 向Scheduler注册日历
    			scheduler.addCalendar("cronCalendar", cronCalendar, true, true);
    		} catch (ParseException e) {
    			e.printStackTrace();
    		}
    

    5.7组合日历

    我们在构建Trigger是只能通过modifiedByCalendar(“日历的name”)方法关联一个已经注册到调度引擎的日历对象,这种情况已经能够满足我们大部分的需求。

    但是如果有跟复杂的需求,比如我们需要在每周的周一至周五,排除晚上8点到24点,情况下按照Trigger配置的周期运行。可以用三种办法实现以上需求

      • HolidayCalendar只能做排除操作
      • HolidayCalendar里面维护了一个TreeSet集合来存放通过addExcludedDate加入的排除日期,所以若是需要排除多个日期,多次调用addExcludedDate方法即可。

       1.可以通过DailyCalendar中的参数invertTimeRange来设置在定义的时间范围内不触发,还是在定义的时间范围外不触发

      根据源码中的描述invertTimeRange=false(默认值)表示在定义的时间范围内不触发

      invertTimeRange=true表示在定义的时间范围外不触发

      2.DailyCalendar的构造参数支持直接输出字符串,比如:new DailyCalendar(“20:00:00”, “21:00:00”)

      3.DailyCalendar可以支持精确到毫秒级别的控制
        

      5.6CronCalendar

      	// 构建SchedulerFactory实例
      		SchedulerFactory schedFact = new StdSchedulerFactory();
      		// 获取Scheduler实例
      		Scheduler scheduler = schedFact.getScheduler();
      		
      		DailyCalendar dailyCalendar = new DailyCalendar("20:00:00", "23:59:59");
      		dailyCalendar.setInvertTimeRange(false);
      		
      		//默认是排除周六和周日的
      		WeeklyCalendar weeklyCalendar = new WeeklyCalendar(dailyCalendar);
      		
      		// 向Scheduler注册日历
      		scheduler.addCalendar("weeklyCalendar", weeklyCalendar, true, true);
      

      写一个时间间隔的日历dailyCalendar,将其作为参数传递给weeklyCalendar就可以了,这样引擎在计算日历日期的时候会先判断dailyCalendar的时间范围,然后再判断weeklyCalendar是时间范围,当条件都满足的是否,触发器才会被触发。


      原文链接:https://blog.csdn.net/qq_38846242/article/details/88696484

        • CronTrigger,这个稍后在详细介绍,通过构建corn表达式来实现。
        • 组合日历,每中日历都有一个构造方法,可以传递一个日历对象进来,通过这样的方式可以构建一个复杂的日历对象。
        • CronTrigger+组合日历的方式。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
priority_queue是C++标准库中的一个容器适配器,它提供了一种基于优先级的元素访问方式。它内部使用堆数据结构来实现,保证了插入和删除操作的时间复杂度都是O(logN)。 priority_queue的使用非常简单,首先需要包含头文件<queue>,然后可以通过以下方式定义一个priority_queue对象: ```cpp #include <queue> std::priority_queue<int> pq; // 默认构造函数,创建一个空的priority_queue,元素类型为int ``` 可以看到,priority_queue可以存储任意类型的元素,只需要在尖括号中指定元素类型即可。 接下来,可以使用以下几个常用的成员函数来操作priority_queue: 1. push(element):将元素element插入到priority_queue中。 2. pop():删除priority_queue中的顶部元素。 3. top():返回priority_queue中的顶部元素,即最大(或最小)值。 4. size():返回priority_queue中元素的个数。 5. empty():判断priority_queue是否为空。 需要注意的是,默认情况下,priority_queue是按照元素的降序进行排列的,即最大值位于顶部。如果需要按照升序排列,可以使用自定义比较函数或者重载元素类型的小于运算符。 以下是一个示例代码,演示了如何使用priority_queue: ```cpp #include <iostream> #include <queue> int main() { std::priority_queue<int> pq; pq.push(10); pq.push(30); pq.push(20); while (!pq.empty()) { std::cout << pq.top() << " "; pq.pop(); } return 0; } ``` 输出结果为:30 20 10,即按照降序排列输出。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值