項目場景:對於定時任務發起的一些任務,由於某些客觀原因,導致任務失敗,希望能夠有一個監聽的定時器,定時輪訓任務狀態表,並重新發起任務調用。
核心思路:
1.定義一個定時器TaskARQCron.java,發起失敗任務掃描。
2.定義一張新的重發狀態表,區分開原任務狀態表,每重新發起一次任務,重發狀態表記錄一條數據。
3.智能識別依賴性任務和非依賴性任務
4.定時任務的掃描的間隔時間設置 2個小時
5.按照日期先後順序執行重發,先失敗,先執行原則,同時針對非依賴性任務,排序執行
6.對於已選中的重發任務,使用ExecutorService、CountDownLatch實現多線程併發執行。
7.將最大重試次數,定義到配置文件,或者任務枚舉類中。
第一步:定時任務表達式
# 每個小時執行一次
cronExpression: 0 0 0/2 * * ?
關於cron表達式的定義,可參考: https://www.cnblogs.com/javahr/p/8318728.html
第二步:定時器類
public class TaskARQCron implements Runnable {
public void run() {
ITaskARQ taskARQ = (ITaskARQ) (ApplicationContextHelper.applicationContext.getBean("taskARQClient"));
taskARQResp = taskARQ.exe();
}
}
第三步:任務處理接口Service
public interface ITaskARQ {
BaseSvcResp exe();
}
第四步:任務處理Service實現
public class TaskARQService implements ITaskARQ {
/** 執行時間到達時, 所有的線程需要依次退出, 主線程纔開始統計執行事物總數 */
private static CountDownLatch countDownLatch;
private ExecutorService executorService;
public BaseSvcResp exe() {
//1.初始化線程池大小
executorService = Executors.newFixedThreadPool(poolSize);
//2.查詢滿足條件的記錄數
List<TblPipbatBatSt> filter = batStMapper.selectByWhiteList(allowList);
//3.初始化CountDownLatch容量大小,用於統計併發線程的結束的狀態
countDownLatch = new CountDownLatch(ableList.size());
//4.根據任務數量,循環創建重發任務線程去執行
for (TblPipbatBatSt batSt : ableList) {
TaskEvent taskEvent = new TaskEvent();
//TODO ... 構建taskEvent對象
executorService.submit(new Worker(job, taskEvent));
}
//5.等待所有線程結束
try {
countDownLatch.await();
logger.info("所有線程執行結束-----------------");
} catch (InterruptedException e) {
//do something....
}
//6.關閉資源
executorService.shutdown();
}
}
第五步:定義Job、JobDetail模式(內部類)
interface Job{
BaseSvcResp execute(TaskEvent taskEvent);
}
static class JobDetail implements Job{
@Override
public BaseSvcResp execute(TaskEvent taskEvent) {
//TODO ... 重新執行任務調用
logger.info("任務重發成功,當前線程:{},當前任務:{}",Thread.currentThread().getName(),taskEvent.toString());
return resp;
}
}
第六步:定義線程類Worker(內部類)
class Worker implements Runnable {
private Job job;
private TaskEvent taskEvent;
Worker (Job job, TaskEvent taskEvent) {
this.job = job;
this.taskEvent = taskEvent;
}
public void run() {
//do something need ...
BaseSvcResp result = this.job.execute(taskEvent);
//do something need ...
countDownLatch.countDown();//代表子線程任務結束
}
}
學習Java的同學注意了!!!
學習過程中遇到什麼問題或者想獲取學習資源的話,歡迎加入Java學習交流羣,羣號碼:543120397 我們一起學Java!