zoukankan      html  css  js  c++  java
  • Quartz源码——Quartz调度器的Misfire处理规则(四)

    Quartz调度器的Misfire处理规则

    调度器的启动和恢复中使用的misfire机制,还需细化!


    SimpleTrigger的misfire机制 默认的 Trigger.MISFIRE_INSTRUCTION_SMART_POLICY !!!

    trig.updateAfterMisfire(cal);
    getMisfireInstruction() ----> misfireInstruction == 0
    ——以当前时间为触发频率立即触发执行

    SimpleScheduleBuilder ssb = SimpleScheduleBuilder.simpleSchedule();
    
    ssb.withMisfireHandlingInstructionFireNow();//1
    ssb.withMisfireHandlingInstructionIgnoreMisfires();//2
    ssb.withMisfireHandlingInstructionNextWithExistingCount();//3
    ssb.withMisfireHandlingInstructionNextWithRemainingCount();//4
    ssb.withMisfireHandlingInstructionNowWithExistingCount();//5
    ssb.withMisfireHandlingInstructionNowWithRemainingCount();//6
    
    //1
    withMisfireHandlingInstructionFireNow  ---> misfireInstruction == 1
    ——以当前时间为触发频率立即触发执行
    ——执行至FinalTIme的剩余周期次数
    ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
    ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
    
    
    
    
    //2
    withMisfireHandlingInstructionIgnoreMisfires ---> misfireInstruction == -1
    —以错过的第一个频率时间立刻开始执行
    ——重做错过的所有频率周期
    ——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率
    ——共执行RepeatCount+1次
    
    //3
    withMisfireHandlingInstructionNextWithExistingCount ---> misfireInstruction == 5
    ——不触发立即执行
    ——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
    ——以startTime为基准计算周期频率,并得到FinalTime
    ——即使中间出现pause,resume以后保持FinalTime时间不变
    
    //4
    withMisfireHandlingInstructionNextWithRemainingCount ---> misfireInstruction = 4
    ——不触发立即执行
    ——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
    ——以startTime为基准计算周期频率,并得到FinalTime
    ——即使中间出现pause,resume以后保持FinalTime时间不变
    
    //5
    withMisfireHandlingInstructionNowWithExistingCount ---> misfireInstruction = 2
    ——以当前时间为触发频率立即触发执行
    ——执行至FinalTIme的剩余周期次数
    ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
    ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
    
    //6
    withMisfireHandlingInstructionNowWithRemainingCount --- >misfireInstruction = 3
    ——以当前时间为触发频率立即触发执行
    ——执行至FinalTIme的剩余周期次数
    ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
    ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
    
    
    MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT 值为 3
    ——此指令导致trigger忘记原始设置的starttime和repeat-count
    ——触发器的repeat-count将被设置为剩余的次数
    ——这样会导致后面无法获得原始设定的starttime和repeat-count值
    

    updateAfterMisfire 方法源码:

     /**
         * <p>
         * Updates the <code>SimpleTrigger</code>'s state based on the
         * MISFIRE_INSTRUCTION_XXX that was selected when the <code>SimpleTrigger</code>
         * was created.
         * </p>
         * 
         * <p>
         * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
         * then the following scheme will be used: <br>
         * <ul>
         * <li>If the Repeat Count is <code>0</code>, then the instruction will
         * be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_NOW</code>.</li>
         * <li>If the Repeat Count is <code>REPEAT_INDEFINITELY</code>, then
         * the instruction will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT</code>.
         * <b>WARNING:</b> using MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 
         * with a trigger that has a non-null end-time may cause the trigger to 
         * never fire again if the end-time arrived during the misfire time span. 
         * </li>
         * <li>If the Repeat Count is <code>&gt; 0</code>, then the instruction
         * will be interpreted as <code>MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT</code>.
         * </li>
         * </ul>
         * </p>
         * */
    /*
    基于在创建SimpleTrigger时选择的MISFIRE_INSTRUCTION_XXX更新SimpleTrigger的状态。
    如果失火指令设置为MISFIRE_INSTRUCTION_SMART_POLICY,则将使用以下方案:
    
    •如果重复计数为0,则指令将解释为MISFIRE_INSTRUCTION_FIRE_NOW。
    •如果重复计数为REPEAT_INDEFINITELY,则指令将解释为MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT。 警告:如果触发器具有非空的结束时间,则使用MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT可能会导致触发器在失火时间范围内到达结束时,不会再次触发。
    •如果重复计数大于0,则指令将解释为MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT。
    */
        @Override
        public void updateAfterMisfire(Calendar cal) {
            int instr = getMisfireInstruction();//获取misfire的值,默认为0
            
            if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)//instr == -1
                return;
            
            if (instr == Trigger.MISFIRE_INSTRUCTION_SMART_POLICY) { //instr == 1
                if (getRepeatCount() == 0) {
                    instr = MISFIRE_INSTRUCTION_FIRE_NOW; //instr = 1
                } else if (getRepeatCount() == REPEAT_INDEFINITELY) {//getRe..Count == -1
    	            //instr = 4
                    instr = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;
                } else {
                    // if (getRepeatCount() > 0)
                    instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;//instr == 2
                }
    		            //instr  == 1
            } else if (instr == MISFIRE_INSTRUCTION_FIRE_NOW && getRepeatCount() != 0) {
    	        //instr  == 3
                instr = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT;
            }
    
            if (instr == MISFIRE_INSTRUCTION_FIRE_NOW) { //instr  == 1
                setNextFireTime(new Date());
    			            //instr  == 5
            } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) {
                Date newFireTime = getFireTimeAfter(new Date());
                while (newFireTime != null && cal != null
                        && !cal.isTimeIncluded(newFireTime.getTime())) {
                    newFireTime = getFireTimeAfter(newFireTime);
    
                    if(newFireTime == null)
                        break;
                    
                    //avoid infinite loop
                    java.util.Calendar c = java.util.Calendar.getInstance();
                    c.setTime(newFireTime);
                    if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {
                        newFireTime = null;
                    }
                }
                setNextFireTime(newFireTime);
                 //instr  == 4
            } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) {
                Date newFireTime = getFireTimeAfter(new Date());
                while (newFireTime != null && cal != null
                        && !cal.isTimeIncluded(newFireTime.getTime())) {
                    newFireTime = getFireTimeAfter(newFireTime);
    
                    if(newFireTime == null)
                        break;
                    
                    //avoid infinite loop
                    java.util.Calendar c = java.util.Calendar.getInstance();
                    c.setTime(newFireTime);
                    if (c.get(java.util.Calendar.YEAR) > YEAR_TO_GIVEUP_SCHEDULING_AT) {
                        newFireTime = null;
                    }
                }
                if (newFireTime != null) {
                    int timesMissed = computeNumTimesFiredBetween(nextFireTime,
                            newFireTime);
                    setTimesTriggered(getTimesTriggered() + timesMissed);
                }
    
                setNextFireTime(newFireTime);
            } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) { //instr  == 2
                Date newFireTime = new Date();
                if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) {
                    setRepeatCount(getRepeatCount() - getTimesTriggered());
                    setTimesTriggered(0);
                }
                
                if (getEndTime() != null && getEndTime().before(newFireTime)) {
                    setNextFireTime(null); // We are past the end time
                } else {
                    setStartTime(newFireTime);
                    setNextFireTime(newFireTime);
                } 
            } else if (instr == MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) { //instr  == 3
                Date newFireTime = new Date();
    
                int timesMissed = computeNumTimesFiredBetween(nextFireTime,
                        newFireTime);
    
                if (repeatCount != 0 && repeatCount != REPEAT_INDEFINITELY) { //repeatCount == -1
                    int remainingCount = getRepeatCount()
                            - (getTimesTriggered() + timesMissed);
                    if (remainingCount <= 0) { 
                        remainingCount = 0;
                    }
                    setRepeatCount(remainingCount);
                    setTimesTriggered(0);
                }
    
                if (getEndTime() != null && getEndTime().before(newFireTime)) {
                    setNextFireTime(null); // We are past the end time
                } else {
                    setStartTime(newFireTime);
                    setNextFireTime(newFireTime);
                } 
            }
    
        }
    

    CronTrigger的misfire机制----默认的 Trigger.MISFIRE_INSTRUCTION_SMART_POLICY !!!
    trig.updateAfterMisfire(cal);
    getMisfireInstruction() ----> misfireInstruction == 0

    CronScheduleBuilder csb = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
    				
    csb.withMisfireHandlingInstructionDoNothing();
    csb.withMisfireHandlingInstructionFireAndProceed();
    csb.withMisfireHandlingInstructionIgnoreMisfires();
    
    withMisfireHandlingInstructionDoNothing ---> misfireInstruction = 2
    ——不触发立即执行
    ——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
    
    withMisfireHandlingInstructionFireAndProceed ---> misfireInstruction = 1
    ——以当前时间为触发频率立刻触发一次执行
    ——然后按照Cron频率依次执行
    
    
    withMisfireHandlingInstructionIgnoreMisfires ---> misfireInstruction = -1
    ——以错过的第一个频率时间立刻开始执行
    ——重做错过的所有频率周期后
    ——当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行
    
    

    updateAfterMisfire 方法源码:

    /**
         * <p>
         * Updates the <code>CronTrigger</code>'s state based on the
         * MISFIRE_INSTRUCTION_XXX that was selected when the <code>CronTrigger</code>
         * was created.
         * </p>
         * 
         * <p>
         * If the misfire instruction is set to MISFIRE_INSTRUCTION_SMART_POLICY,
         * then the following scheme will be used: <br>
         * <ul>
         * <li>The instruction will be interpreted as <code>MISFIRE_INSTRUCTION_FIRE_ONCE_NOW</code>
         * </ul>
         * </p>
         */
    /*
    	根据创建CronTrigger时选择的MISFIRE_INSTRUCTION_XXX更新CronTrigger的状态。
    
    如果失火指令设置为MISFIRE_INSTRUCTION_SMART_POLICY,则将使用以下方案:
    
    •指令将解释为MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
    */
         
        @Override
        public void updateAfterMisfire(org.quartz.Calendar cal) {
            int instr = getMisfireInstruction();//获取misfire的值,默认为0
    
            if(instr == Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY)//instr  == -1
                return;
    
            if (instr == MISFIRE_INSTRUCTION_SMART_POLICY) {//instr  == 0
                instr = MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;//instr = 1
            }
    
            if (instr == MISFIRE_INSTRUCTION_DO_NOTHING) {//instr  == 2
                Date newFireTime = getFireTimeAfter(new Date());
                while (newFireTime != null && cal != null
                        && !cal.isTimeIncluded(newFireTime.getTime())) {
                    newFireTime = getFireTimeAfter(newFireTime);
                }
                setNextFireTime(newFireTime);
            } else if (instr == MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {//instr  == 1
                setNextFireTime(new Date());
            }
        }
    
    
    
    

    参考文章:https://my.oschina.net/chenleijava/blog/109904


    欢迎访问我的csdn博客,我们一同成长!

    "不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!"

    博客首页http://blog.csdn.net/u010648555

  • 相关阅读:
    深入理解java:2.3.1. 并发编程concurrent包 之Atomic原子操作(循环CAS)
    深入理解java:2.3. 并发编程 java.util.concurrent包
    深入理解java:2.2. 同步锁Synchronized及其实现原理
    深入理解java:2.1. volatile的使用及其原理
    深入理解java:2. 多线程机制
    深入理解java:1.3.2 JVM监控与调优
    深入理解java:1.3.1 JVM内存区域的划分(运行时数据区)
    深入理解java:1.3. 垃圾收集
    深入理解java:1.2. 字节码执行引擎
    线程的等待与唤醒,实现if...else里面的值交互依次输出
  • 原文地址:https://www.cnblogs.com/aflyun/p/6769748.html
Copyright © 2011-2022 走看看