從一條阿里編碼規範談線程池的使用

最近在看阿里Java編程規範,有一條引起了我的注意:

【強制】線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。
說明:Executors 返回的線程池對象的弊端如下:

  1. FixedThreadPoolSingleThreadPool: 允許的請求隊列長度爲Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM。
  2. CachedThreadPoolScheduledThreadPool: 允許的創建線程數量爲 Integer.MAX_VALUE,可能會創建大量的線程,從而導致 OOM。

平時沒怎麼注意這一點,一般用的多的還是FixedThreadPoolSingleThreadPool。那怎麼理解這條規範呢?首先,ThreadPoolExecutor是更底層的類,直接用它的構造方法,可以讓我們對創建的線程池有更強的控制。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), handler);
}

我們來看下ThreadPoolExecutor的參數設定:

  • corePoolSize:核心線程數(就算有空閒線程,也不會低於這個數)
  • maximumPoolSize:最大線程數
  • keepAliveTime:最大存活時間(超過corePoolSize數量的線程空閒下最大存活時間)
  • unit:時間單位
  • workQueue:工作隊列(核心線程滿後,任務會進入這裏)
  • handler:任務滿負荷(超出最大線程數和工作隊列上限之和)後的處理策略

其中處理策略有四種:

  • AbortPolicy:默認策略,在需要拒絕任務時拋出RejectedExecutionException
  • CallerRunsPolicy:直接在 execute 方法的調用線程中運行被拒絕的任務,如果線程池已經關閉,任務將被丟棄
  • DiscardPolicy:直接丟棄任務
  • DiscardOldestPolicy:丟棄隊列中等待時間最長的任務,並執行當前提交的任務,如果線程池已經關閉,任務將被丟棄

除此之外我們也可以自定義處理策略。

作爲對比,我們看下FixedThreadPool的實現:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

可見它實際上就是個簡化版的ThreadPoolExecutor,通過固定線程數,然後指定工作隊列長度爲無限(不傳長度代表容量無限)。這樣確實可能會造成任務無限堆積,引起OOM的問題。所以阿里的規範建議我們直接使用更底層的ThreadPoolExecutor,把處理策略之類的都提前設定好。

不過規範也不是死的,在實際情況中也無法避免使用FixedThreadPool等更高層的實現。一方面是因爲使用起來更加方便,另一方面也是有時候使用ThreadPoolExecutor並沒有明顯的好處。例如:線程池中分配的任務都是關鍵任務,無法被丟棄,然後因爲性能考慮也無法被execute線程同步執行,這樣就很難定義一個合適的處理策略,不如直接使用FixedThreadPool。就算有OOM的風險,那也只能說在多種風險權衡下做的一個評估和取捨。

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