SpringBoot 線程池配置 實現AsyncConfigurer接口方法


 

 

 目的是:
  通過實現AsyncConfigurer自定義線程池,包含異常處理
  實現AsyncConfigurer接口對異常線程池更加細粒度的控制
*a) 創建線程自己的線程池
  b) 對void方法拋出的異常處理的類AsyncUncaughtExceptionHandler
 

個人初步理解

 一、線程池是為突然大量爆發的線程設計的,通過有限的幾個固定線程為大量的操作服務,減少了創建和銷毀線程所需的時間,
從而提高效率。如果一個線程的時間非常長,就沒必要用線程池了(不是不能作長時間操作,而是不宜。),
況且還不能控制線程池中線程的開始、掛起、和中止。
二、利用線程池啟動線程
Thread udpThread = new Thread(udp);
poolTaskExecutor.execute(udpThread);
獲取當前線程池活動的線程數:
int count = poolTaskExecutor.getActiveCount();
logger.debug("[x] - now threadpool active threads totalNum : " +count);
三、配置解釋
當一個任務通過execute(Runnable)方法欲添加到線程池時:
1、 如果此時線程池中的數量小於corePoolSize,即使線程池中的線程都處於空閑狀態,也要創建新的線程來處理被添加的任務。
2、 如果此時線程池中的數量等於 corePoolSize,但是緩沖隊列 workQueue未滿,那么任務被放入緩沖隊列。
3、如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量小於maximumPoolSize,建新的線程來處理被添加的任務。
4、 如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量等於maximumPoolSize,那么通過 handler所指定的策略來處理此任務。
也就是:處理任務的優先級為:核心線程corePoolSize、任務隊列workQueue、最大線程 maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。
5、 當線程池中的線程數量大於 corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態的調整池中的線程數。
allowCoreThreadTimeout:允許核心線程超時
rejectedExecutionHandler:任務拒絕處理器

兩種情況會拒絕處理任務:
當線程數已經達到maxPoolSize,切隊列已滿,會拒絕新任務
當線程池被調用shutdown()后,會等待線程池里的任務執行完畢,再shutdown。如果在調用shutdown()和線程池真正shutdown之間提交任務,會拒絕新任務
線程池會調用rejectedExecutionHandler來處理這個任務。如果沒有設置默認是AbortPolicy,會拋出異常
ThreadPoolExecutor類有幾個內部實現類來處理這類情況:
AbortPolicy 丟棄任務,拋運行時異常
CallerRunsPolicy 執行任務
DiscardPolicy 忽視,什么都不會發生
DiscardOldestPolicy 從隊列中踢出最先進入隊列(最后一個執行)的任務
實現RejectedExecutionHandler接口,可自定義處理器

廢話不多說 上代碼 環境:IDEA +SpringBoot+maven

   一、線程池配置類實現AsyncConfigurer 接口:

復制代碼
@Component
public class MyAsyncConfigurer implements AsyncConfigurer {

    private static final Logger log = LoggerFactory.getLogger(MyAsyncConfigurer.class);

    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        threadPool.setCorePoolSize(2);//當前線程數
        threadPool.setMaxPoolSize(120);// 最大線程數
        threadPool.setQueueCapacity(1);//線程池所使用的緩沖隊列
        threadPool.setWaitForTasksToCompleteOnShutdown(true);//等待任務在關機時完成--表明等待所有線程執行完
        threadPool.setAwaitTerminationSeconds(60 * 15);// 等待時間 (默認為0,此時立即停止),並沒等待xx秒后強制停止
        threadPool.setThreadNamePrefix("MyAsync-");//  線程名稱前綴
        threadPool.initialize(); // 初始化
        System.out.println("--------------------------》》》開啟異常線程池");
        return threadPool;
    }


    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

        return new MyAsyncExceptionHandler();
    }

    /**
     * 自定義異常處理類
     * @author hry
     *
     */
    class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

        //手動處理捕獲的異常
        @Override
        public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
            System.out.println("-------------》》》捕獲線程異常信息");
            log.info("Exception message - " + throwable.getMessage());
            log.info("Method name - " + method.getName());
            for (Object param : obj) {
                log.info("Parameter value - " + param);
            }
        }

    }
復制代碼

 

 

 

    二、使用簡單無參數異步線程進行測試

      

復制代碼
 @Override
    @Async
    public String asyncMethodWithVoidReturnType() {

        System.out.println("線程名稱:"+Thread.currentThread().getName() + " be ready to read data!");
        try {
            Thread.sleep(1000 * 5);
            System.out.println("---------------------》》》無返回值延遲3秒:");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "已進入到異步";
    }
復制代碼

 

 

 

    三、0--3秒內連續訪問如下結果

 

 

復制代碼
線程名稱:MyAsync-1 be ready to read data!
線程名稱:MyAsync-2 be ready to read data!
線程名稱:MyAsync-3 be ready to read data!
線程名稱:MyAsync-4 be ready to read data!
線程名稱:MyAsync-5 be ready to read data!
線程名稱:MyAsync-6 be ready to read data!
線程名稱:MyAsync-7 be ready to read data!
線程名稱:MyAsync-8 be ready to read data!
MyAsync-1---------------------》》》無返回值延遲5秒:
線程名稱:MyAsync-1 be ready to read data!
MyAsync-2---------------------》》》無返回值延遲5秒:
線程名稱:MyAsync-2 be ready to read data!
MyAsync-3---------------------》》》無返回值延遲5秒:
MyAsync-4---------------------》》》無返回值延遲5秒:
MyAsync-5---------------------》》》無返回值延遲5秒:
MyAsync-6---------------------》》》無返回值延遲5秒:
MyAsync-7---------------------》》》無返回值延遲5秒:
MyAsync-8---------------------》》》無返回值延遲5秒:
MyAsync-1---------------------》》》無返回值延遲5秒:
MyAsync-2---------------------》》》無返回值延遲5秒:
復制代碼

 

     如上可以看出 線程池發揮作用 多個線程訪問如果超過核心線程數+隊列數 變新創建線程,如果有線程

 空閑下來會繼續分配,以此來提高效率。我是利用postMain 來進行的測試,以驗證上面所說的理論問題。。

  實際應用中比這個復雜得多。。。。。。。。

     四、如果想要手動捕獲異常信息  如下代碼 即可

  throw new IllegalArgumentException(s);
將上面代碼 放在需要捕獲信息的中
在線程池配置中 MyAsyncExceptionHandler 的方法中 即會捕捉到信息。。。。。。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM