不知道你們在用Quartz的時候 有沒有遇到這樣一種狀況:html
觸發器設定每3秒鐘觸發一次 ,可是工做須要10秒鐘的執行時間.所以,在一次任務結束執行前,觸發器已經錯失觸發java
當這種狀況下咱們怎麼處理呢,讓咱們一塊兒學習一下......ide
仍是先貼代碼:學習
job類:StatefulDumbJob.javaui
/** * Created with IntelliJ IDEA. * Description: * User: zhubo * Date: 2017-10-24 * Time: 17:25 */ @PersistJobDataAfterExecution @DisallowConcurrentExecution public class StatefulDumbJob implements Job { // 靜態常量,做爲任務在調用間,保持數據的鍵(key) // NUM_EXECUTIONS,保存的計數每次遞增1 // EXECUTION_DELAY,任務在執行時,中間睡眠的時間。本例中睡眠時間過長致使了錯失觸發 public static final String NUM_EXECUTIONS = "NumExecutions"; public static final String EXECUTION_DELAY = "ExecutionDelay"; @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 任務執行的時間 SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); String jobRunTime = dateFormat.format(Calendar.getInstance().getTime()); System.err.println("---" + context.getJobDetail().getKey().getName() + " 在 : [" + jobRunTime + "] 執行了!!"); // 任務執行計數 累加 JobDataMap map = context.getJobDetail().getJobDataMap(); int executeCount = 0; if (map.containsKey(NUM_EXECUTIONS)) { executeCount = map.getInt(NUM_EXECUTIONS); } executeCount++; map.put(NUM_EXECUTIONS,executeCount); // 睡眠時間: 由調度類從新設置值 ,本例爲 睡眠10s long delay = 5000L; if (map.containsKey(EXECUTION_DELAY)) { delay = map.getLong(EXECUTION_DELAY); } try{ Thread.sleep(delay); }catch (Exception e){ } // 睡眠醒來後,打印任務執行結束的信息 System.err.println(" -" + context.getJobDetail().getKey().getName() + " 完成次數 : " + executeCount ); } }
調度類: MisfireExample.javaspa
import static org.quartz.DateBuilder.nextGivenSecondDate; import static org.quartz.JobBuilder.newJob; import static org.quartz.SimpleScheduleBuilder.simpleSchedule; import static org.quartz.TriggerBuilder.newTrigger; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerFactory; import org.quartz.SchedulerMetaData; import org.quartz.SimpleTrigger; import org.quartz.impl.StdSchedulerFactory; public class MisfireExample { public static void main(String[] args) throws Exception { MisfireExample example = new MisfireExample(); example.run(); } public void run() throws Exception { // 任務執行的時間 格式化 SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); System.out.println("--------------- 初始化 -------------------"); // 下一個第15秒 Date startTime = nextGivenSecondDate(null, 15); // statefulJob1 每3s運行一次,但它會延遲10s JobDetail job = newJob(StatefulDumbJob.class) .withIdentity("statefulJob1", "group1") .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L) // 設置參數:睡眠時間 10s .build(); SimpleTrigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startAt(startTime) .withSchedule( simpleSchedule().withIntervalInSeconds(3) .repeatForever()).build(); Date ft = sched.scheduleJob(job, trigger); System.out.println(job.getKey().getName() + " 將在: " + dateFormat.format(ft) + " 時運行.而且重複: " + trigger.getRepeatCount() + " 次, 每次間隔 " + trigger.getRepeatInterval() / 1000 + " 秒"); // statefulJob2 將每3s運行一次 , 但它將延遲10s , 而後不斷的迭代 job = newJob(StatefulDumbJob.class) .withIdentity("statefulJob2", "group1") .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L)// 設置參數:睡眠時間 10s .build(); trigger = newTrigger() .withIdentity("trigger2", "group1") .startAt(startTime) .withSchedule( simpleSchedule() .withIntervalInSeconds(3) .repeatForever() // 設置錯失觸發後的調度策略 .withMisfireHandlingInstructionNowWithRemainingCount() ) .build(); ft = sched.scheduleJob(job, trigger); System.out.println(job.getKey().getName() + " 將在: " + dateFormat.format(ft) + " 時運行.而且重複: " + trigger.getRepeatCount() + " 次, 每次間隔 " + trigger.getRepeatInterval() / 1000 + " 秒"); System.out.println("------- 開始調度 (調用.start()方法) ----------------"); sched.start(); // 給任務留時間運行 Thread.sleep(600L * 1000L); sched.shutdown(true); System.out.println("------- 調度已關閉 ---------------------"); // 顯示一下 已經執行的任務信息 SchedulerMetaData metaData = sched.getMetaData(); System.out.println("~~~~~~~~~~ 執行了 " + metaData.getNumberOfJobsExecuted() + " 個 jobs."); } }
-------------------------------------我是分割線----------------------------------------------------------線程
先說明 一個詞 : misfire -- 指的是 錯過了觸發時間 code
你會注意到2個觸發器具備相同的時間安排,相同的任務orm
觸發器設定每3秒鐘觸發一次,可是工做須要10秒鐘的執行時間htm
所以,在一次任務結束執行前,觸發器已經錯失觸發(除非’錯失觸發時限’被設置爲超過7秒)。
其中第二個任務設置本身的錯失觸發指示:.withMisfireHandlingInstructionNowWithRemainingCount()
因此當檢測到丟失觸發時,不會當即觸發,而是忽略本次安排到下一個預約時間去觸發
咱們的結論 :
a) 本範例中,觸發的間隔被設置爲3秒,可是因爲任務體執行間睡眠10秒,致使了錯失觸發的產生。
b) 實際運行的效果,2個任務執行的間隔爲10秒。
c) 因爲丟失觸發時,job2的策略是當即觸發,而job1是等待下一次機會觸發。因此job2會趕在job1的前頭,最終運行次數大於job1。
Quartz 的 Misfire處理規則:
調度(scheduleJob)或恢復調度(resumeTrigger,resumeJob)後不一樣的misfire對應的處理規則
CronTrigg
CronTrigger
withMisfireHandlingInstructionDoNothing
——不觸發當即執行
——等待下次Cron觸發頻率到達時刻開始按照Cron頻率依次執行
withMisfireHandlingInstructionIgnoreMisfires
——以錯過的第一個頻率時間馬上開始執行
——重作錯過的全部頻率週期後
——當下一次觸發頻率發生時間大於當前時間後,再按照正常的Cron頻率依次執行
withMisfireHandlingInstructionFireAndProceed
——以當前時間爲觸發頻率馬上觸發一次執行
——而後按照Cron頻率依次執行
SimpleTrigger
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值
另外,若是任務數超過了Quartz的線程池中的線程數時,也會發生相似的狀況 兄弟們能夠參考一下下面的這篇博文:
http://www.cnblogs.com/makemelaugh/archive/2012/06/17/2533105.html