任務流程圖
用戶通過該框架只需在配置文件中配置好繼承了DTJobBase類的路徑和定時任務表達式,即可開啓定時任務,屬於非常輕量級的定時任務框架。具體流程圖如下:
定時類設計
定時任務抽象類,該類對外提供了一個jobRun()抽象方法,使用時只需繼承該類,然後實現該抽象方法即可。
/**
* 任務抽象類/已下僅含有核心代碼
* @author 康駐關
* Fri Jul 19 09:00:00 CST 2019
*/
public abstract class DTJobBase extends Thread {
private Object _result = null;//用於存放任務執行返回結果
private Thread _t = null;//用於執行當前線程
private Exception _e = null;//用於存放捕獲異常
private long _timeStart = 0;//任務開始時間
private long _timeCost = 0;//任務消耗時間
/**
* 自定義任務接口
* @return
* @throws Exception
*/
public abstract Object jobRun() throws Exception;
/**
* 執行任務並記錄任務花費時間
*/
@Override
public void run() {
this._timeStart = System.currentTimeMillis();
try {
_result = jobRun();
} catch (Exception ex) {
this._e = ex;
}
this._timeCost = System.currentTimeMillis() - this._timeStart;
}
}
定時任務工具類設計
定時任務工具類設計,主要是
initProperties(); // 初始化配置
initJobs(); //初始化Job任務
initWatcher(); //掃描並執行定時任務
這三個方法。在checkJobs()方法裏我有一段代碼,不知道是否可以優化程序,有大神看到後跟我留言,謝謝了!
/**
* 開始定時任務工具類/已下僅含有核心代碼
* @author 康駐關
* Fri Jul 19 09:00:00 CST 2019
*/
public class CTUtil {
private static HashMap<String, String> _CTProperties = null; // 配置文件列表,key爲類名,value爲克隆表達式
private static HashMap<String, CTJobBase> _CTJobs = null; // 定時任務列表,key爲任務token,value爲定時任務
private static Boolean _Suspended = false; // 任務暫停
private static Watcher _Watcher = null;
/**
* 任務檢測類
*/
protected static class Watcher implements Runnable {
private boolean _Cancelled = false;// 是否取消任務
private Thread _thread = null;// 啓動任務線程
int _SleepMilliSeconds = 0; // 任務掃描間隔
public Watcher(int sleepMilliSeconds) {
if (_thread == null)
_thread = new Thread(this);
this._SleepMilliSeconds = sleepMilliSeconds;
}
public void Start() //篇幅有限省略
public void Cancel() //篇幅有限省略
@Override
public void run() {
// 循環掃描定時任務
while (!_Cancelled) {
try {
TimeUnit.MILLISECONDS.sleep(_SleepMilliSeconds);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
checkJobs();
}
}
protected Boolean isSuspended() //篇幅有限省略
protected void suspend() //篇幅有限省略
protected void resume() //篇幅有限省略
private synchronized void checkJobs() {
if (_Suspended)
return;
try {
Date _checkTime = new Date();
_CTJobs.forEach((k, v) -> {
System.out.println(v.getClass().getName());
// 如果當前任務沒有執行,並且當前時間在當前定時任務執行時間之後,執行該任務
if (!v.isPending() && _checkTime.after(v.getNextTrigger()))
v.start();
// 我覺得這裏可以優化,如果當前的檢測時間在當前這個任務下次執行之前,同時下次任務執行時間-當前檢測時間小於最小休眠時間,則將休眠時間設爲當前最小值
// 可以有效降低循環次數,但沒有測試性能是否有優化
// _SleepMilliSeconds = (int)
// (((v.getNextTrigger().getTime() - _checkTime.getTime()) >
// 0
// && (v.getNextTrigger().getTime() - _checkTime.getTime())
// < _SleepMilliSeconds)
// ? (v.getNextTrigger().getTime() - _checkTime.getTime()) :
// _SleepMilliSeconds);
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void suspend() //篇幅有限省略
public static void resume() //篇幅有限省略
public static Boolean isSuspended() //篇幅有限省略
/**
* 手動開啓定時任務
*
* @param token
* @return
*/
protected static int execManually(final String token) //篇幅有限省略
/**
* 獲取某個定時任務克隆表達式
*
* @param pName
* @return
*/
protected static String getCTProperties(final String pName) {
if (_CTProperties == null)
initProperties();
if (_CTProperties.containsKey(pName))
return _CTProperties.get(pName);
else
return null;
}
private static void initProperties() {
if (_CTProperties == null)
_CTProperties = new HashMap<String, String>();
Properties p = new Properties();
File f = new File("conf" + File.separator + "ct.properties");
FileInputStream fs = null;
try {
fs = new FileInputStream(f);
p.load(fs);
p.forEach((k, v) -> {
if (!_CTProperties.containsKey(k))
_CTProperties.put(String.valueOf(k), String.valueOf(v));
});
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fs != null)
try {
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void initWatcher() {
if (_Watcher == null)
_Watcher = new Watcher(100);
_Watcher.Start();
// if(DebugInfo.isDebug()){
// _Watcher.suspend();
// }
}
public static void initCrontabJobService() {
initProperties();
initJobs();
initWatcher();
}
/**
* 停止所有定時任務服務
*/
public static void stopCrontabJobService() //篇幅有限省略
/**
* 初始化定時任務列表
*/
public static void initJobs() {
if (_CTJobs == null)
_CTJobs = new HashMap<String, CTJobBase>();
_CTProperties.forEach((k, v) -> {
try {
CTJobBase ctj;
ctj = (CTJobBase) Class.forName(k).newInstance();
ctj.setCronExp(v);
_CTJobs.put("CT-" + HashUtil.getSHA1(k + v), ctj);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
});
}
}
配置文件
配置克隆表達式的文件內容,我這裏配置的測試是每分鐘執行一次任務
#-----------------------
#Crontab Jobs configure
#-----------------------
#com.kzg.ct.d.TestCTJob = 0 0 0,12 * * ?
#Triggered every 1 minute
com.kzg.ct.d.TestCTJob = 0 * * * * ?
測試結果
public static void main(String[] args) {
CTUtil.initCrontabJobService();
}
尊重原創,如果轉發請標明鏈接,謝謝! 項目: 鏈接