多線程應用:定時任務重發機制實現

項目場景:對於定時任務發起的一些任務,由於某些客觀原因,導致任務失敗,希望能夠有一個監聽的定時器,定時輪訓任務狀態表,並重新發起任務調用。

核心思路:
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!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章