1. 程式人生 > >JDK執行緒池的拒絕策略

JDK執行緒池的拒絕策略

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

       經核查,該問題是由於立單介面內部沒有成功呼叫接續的 “更新來電原因介面”導致的,接續測更新來電原因介面編碼: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]執行緒池的拒絕策略,是指當任務新增到執行緒池中被拒絕,而採取的處理措施。當任務新增到執行緒池中之所以被拒絕,可能是由於:第一,執行緒池異常關閉。第二,任務數量超過執行緒池的最大限制