1. 程式人生 > >JDK線程池的拒絕策略

JDK線程池的拒絕策略

線程 common 大於 des demo void policy integer rri

關於新疆服務請求未帶入來話原因的問題

經核查,該問題是由於立單接口內部沒有成功調用接續的 “更新來電原因接口”導致的,接續測更新來電原因接口編碼:NGCCT_UPDATESRFLAG_PUT ,立單接口調用代碼如下:

final Map<String, Object> paramsMap = outputObject.getBean();
paramsMap.put("provCode", provCode);
paramsMap.put("tenantId", MapUtils.getString(inputObject.getParams(), "tenantId"));
TaskEngine.getInstance().submit(
new Runnable() { @Override public void run() { callContactRel(paramsMap);[zhai1] backWriteWrkfm(paramsMap); } });

立單接口中使用起多線程異步調用方式,更新來電原因方法內部記錄日誌,由於線程內部日誌無法在火眼系統查看,當出現該問題時,

1.多次找在線運維人員查看主機上的日誌,均未發現更新來話原因方法內部記錄的日誌;

2.登陸csf平臺查詢該接口的調用記錄,根據出現問題的流水號均未查到相關調用記錄;

3.核查調用更新來電原因方法內部catch中如表的錯誤記錄,也未發現問題;

根據火眼上上下文日誌,確定程序一定運行到了啟動多線程的地方,遂懷疑線程池的問題,

該處啟用多線程使用的是 TaskEngine工具提供的獲取線程池,使用池中資源執行任務。

經核查TaskEngine類發現該類在初始化的時候會創建一個線程池,核心線程數為1,最大線程數為30的線程池,代碼如下:

private static TaskEngine instance = new TaskEngine();
public static TaskEngine getInstance() {

    return instance;

}
private TaskEngine() {

    executor 
= new ThreadPoolExecutor(1, 30,180L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() { final AtomicInteger threadNumber = new AtomicInteger(1); public Thread newThread(Runnable runnable) { // Use our own naming scheme for the threads. Thread thread = new Thread(Thread.currentThread().getThreadGroup(), runnable, "TaskEngine-pool-" + threadNumber.getAndIncrement(), 0); // Make workers daemon threads. thread.setDaemon(true); if (thread.getPriority() != Thread.NORM_PRIORITY) { thread.setPriority(Thread.NORM_PRIORITY); } return thread; } }); }

該線程池構造時尚未指明 拒絕策略 [zhai2] 因此會默認使用 AbortPolicy

JDK提供的ThreadPoolExecutor 線程池有四種 拒絕策略:

AbortPolicy 當任務添加到線程池中被拒絕時,它將拋出 RejectedExecutionException 異常。

CallerRunsPolicy 當任務添加到線程池中被拒絕時,會在線程池當前正在運行的Thread線程池中處理被拒絕的任務。

DiscardOldestPolicy 當任務添加到線程池中被拒絕時,線程池會放棄等待隊列中最舊的未處理任務,然後將被拒絕的任務添加到等待隊列中。

DiscardPolicy 當任務添加到線程池中被拒絕時,線程池將丟棄被拒絕的任務。

工程中使用的默認的策略,會不會存在一種情況,在某一個時刻,使用TaskEngine類獲取線程池來執行任務時,30個線程同時被使用,導致創建任務數大於最大線程數的限制,該任務將無法被成功執行。

Demo驗證:

1.使用與項目中相同的線程池執行數據入庫操作,模擬設置最大線程數10,核心線程1個,拒絕策略默認:

@RequestMapping(value = "/testThread")

public String testThread(){

    final CommonCfgCode commonCfgCode = new CommonCfgCode();

    commonCfgCode.setCodeTypeCd("Thread");

    TaskEngine taskEngine = TaskEngine.getInstance();

    for(int i=0;i<100;i++){

        taskEngine.submit(new Runnable() {

            @Override

            public void run() {

                testService.save(commonCfgCode);

            }

        });

    }

    return "SUCCESS";

}

循環執行100個任務進行如表操作拋出:

java.util.concurrent.RejectedExecutionException異常,與該策略描述一致。

技術分享圖片

查看如表數據:僅如表10條數據;

技術分享圖片

2.將拒絕策略修改為:CallerRunsPolicy 其它不變;

無報錯,查詢數據:如表100條;(110條中包含使用默認拒絕拋異常策略如表的10條)

技術分享圖片

Demo git路徑:https://git.lug.ustc.edu.cn/zhaiyt/mylife.git

由於該問題僅在新疆出現,出現的場景無法預知,請各位評審是否可以修改項目中TaskEngine類。


[zhai1]調用接續接口更新來話原因方法

[zhai2]線程池的拒絕策略,是指當任務添加到線程池中被拒絕,而采取的處理措施。當任務添加到線程池中之所以被拒絕,可能是由於:第一,線程池異常關閉。第二,任務數量超過線程池的最大限制

JDK線程池的拒絕策略