1. 程式人生 > >Quartz:任務排程實現原理

Quartz:任務排程實現原理

什麼是Quartz

Quartz是一個完全由Java編寫的開源作業排程框架,為在Java應用程式中進行作業排程提供了簡單卻強大的機制。

Quartz允許開發人員根據時間間隔來排程作業。

它實現了作業和觸發器的多對多的關係,還能把多個作業與不同的觸發器關聯。簡單地建立一個org.quarz.Job介面的Java類。

Quartz的特點

作為一個優秀的開源排程框架,Quartz 具有以下特點:

① 強大的排程功能,例如支援豐富多樣的排程方法,可以滿足各種常規及特殊需求;

② 靈活的應用方式,例如支援任務和排程的多種組合方式

,支援排程資料的多種儲存方式;

③ 分散式和叢集能力,Terracotta 收購後在原來功能基礎上作了進一步提升。

④ Quartz 很容易與 Spring 整合實現靈活可配置的排程功能。

 

Quartz專用詞彙說明

下面是本文中用到的一些專用詞彙,在此宣告:

scheduler任務排程器

trigger觸發器,用於定義任務排程時間規則

job任務,即被排程的任務

misfire錯過的,指本來應該被執行但實際沒有被執行的任務排程

 

Quartz任務排程基本實現原理:

Quartz任務排程的核心元素為:Scheduler——任務排程器、Trigger——觸發器、Job——任務。

其中trigger和job是任務排程的元資料,scheduler是實際執行排程的控制器。

Trigger

  • 是用於定義排程時間的元素,即按照什麼時間規則去執行任務。
  • Quartz中主要提供了四種類型的trigger:SimpleTrigger,CronTirgger,DateIntervalTrigger,和NthIncludedDayTrigger。
  • 這四種trigger可以滿足企業應用中的絕大部分需求。

Job

  • 用於表示被排程的任務。
  • 主要有兩種型別的job:無狀態的(stateless)和有狀態的(stateful)
  • 對於同一個trigger來說,有狀態的job不能被並行執行,只有上一次觸發的任務被執行完之後,才能觸發下一次執行。
  • Job主要有兩種屬性:volatility和durability,其中volatility表示任務是否被持久化到資料庫儲存,而durability表示在沒有trigger關聯的時候任務是否被保留。兩者都是在值為true的時候任務被持久化或保留。
  • 一個job可以被多個trigger關聯,但是一個trigger只能關聯一個job

Scheduler

  • scheduler由scheduler工廠建立:DirectSchedulerFactory或者StdSchedulerFactory。
  • StdSchedulerFactory使用較多,因為DirectSchedulerFactory使用起來不夠方便,需要作許多詳細的手工編碼設定。
  • Scheduler主要有三種:RemoteMBeanScheduler,RemoteScheduler和StdScheduler。StdScheduler 為最常用。

Quartz 執行緒檢視

  在Quartz中,有兩類執行緒,Scheduler排程執行緒和任務執行執行緒,其中任務執行執行緒通常使用一個執行緒池維護一組執行緒。

 

Scheduler排程執行緒主要有兩個:執行常規排程的執行緒,和執行misfiredtrigger的執行緒。

常規排程執行緒:輪詢儲存的所有trigger,如果有需要觸發的trigger,即到達了下一次觸發的時間,則從任務執行執行緒池獲取一個空閒執行緒,執行與該trigger關聯的任務。

Misfire執行緒:是掃描所有的trigger,檢視是否有misfiredtrigger,如果有的話根據misfire的策略分別處理(fire now OR wait for the next fire)。

 

Quartz Job資料儲存

Quartz中的trigger和job需要儲存下來才能被使用。

Quartz中有兩種儲存方式:RAMJobStore,JobStoreSupport。

RAMJobStore是將trigger和job儲存在記憶體中,而JobStoreSupport是基於jdbc將trigger和job儲存到資料庫中。

RAMJobStore的存取速度非常快,但是由於其在系統被停止後所有的資料都會丟失,所以在叢集應用中,必須使用JobStoreSupport。

任務排程器排程的時序:

 

在這裡將幾個重要的類呼叫的過程以序列圖的形式展現出來,上半部分展現的是啟動過程,下半部分展現的是任務排程的過程。

步驟1.使用者首先需要生成一個排程器工廠SchedulerFactory,可以用下面的方式實現自己的定製化:

Properties properties=new Properties();    
properties.put("org.quartz.threadPool.class","org.quartz.simpl.SimpleThreadPool");
properties.put("org.quartz.threadPool.threadCount","10");
SchedulerFactory sf=new StdSchedulerFactory(properties);

步驟2.然後通過getScheduler()方法從排程器工廠裡得到排程器例項,首先查詢有沒有這樣的排程器,沒有的話,就生成一個,有的話直接返回。所以得到的一般是單例,即預設的排程器。

步驟3.Scheduler有一個QuartzSchedulerThread(Thread的子類)屬性,在scheduler例項化的時候,例項化了一個物件,並用ThreadExecutor啟動該執行緒物件。該執行緒就是排程執行緒,主要任務就是不停的從JobStore中獲取即將被觸發的觸發器(預設30s排程一次)。在這個時候排程執行緒雖然啟動,但是處於pause狀態。

步驟4.接下來是任務排程的部分:

Scheduler scheduler=sf.getScheduler();
scheduler.addJobListener(new TaskListener());
scheduler.scheduleJob(jobDetail, simpleTrigger);
scheduler.start();

client通過scheduleJob()方法將任務和觸發器儲存在JobStore中,通過start()方法將QuartzSchedulerThread的pause狀態設為false,通知排程執行緒執行任務,此後排程執行緒不停的從JobStore中去取即將觸發的任務。

 

任務執行的時序:

 

上半部分展現的是任務執行之前準備工作的時序,下半部分展現的是任務執行的時序。

步驟1.排程執行緒首先去執行緒池中獲取可用的執行緒,如果沒有的話,就阻塞。

步驟2.從JobStore(從儲存介質中獲取觸發器,儲存介質可以是記憶體也可以是資料庫)獲取(接下來30s內的)觸發器,然後等待該觸發器觸發。

步驟3.排程執行緒建立一個JobRunShell(就是一個Runnable),然後從執行緒池中呼叫執行緒執行該任務。

接下來就是任務執行的時序:

步驟4.獲取trigger、JobDetail以及生成Job例項,然後執行job的execute介面函式。

 

持久化的任務的執行時序:

 

以上就是Quartz的基本工作流程。

參考來源:https://www.cnblogs.com/zhangchengzhangtuo/p/5705672.html