ThreadPoolExecutor運轉機制詳解

最近發現幾起對ThreadPoolExecutor的誤用,其中包括自己,發現都是因爲沒有仔細看註釋和內部運轉機制,想當然的揣測參數導致,先看一下新建一個ThreadPoolExecutor的構建參數:

[java] view plaincopy
  1. public ThreadPoolExecutor(int corePoolSize,  
  2.                           int maximumPoolSize,  
  3.                           long keepAliveTime,  
  4.                           TimeUnit unit,  
  5.                           BlockingQueue<Runnable> workQueue,  
  6.                           ThreadFactory threadFactory,  
  7.                           RejectedExecutionHandler handler)  

看這個參數很容易讓人以爲是線程池裏保持corePoolSize個線程,如果不夠用,就加線程入池直至maximumPoolSize大小,如果還不夠就往workQueue里加,如果workQueue也不夠就用RejectedExecutionHandler來做拒絕處理。

但實際情況不是這樣,具體流程如下:

1)當池子大小小於corePoolSize就新建線程,並處理請求

2)當池子大小等於corePoolSize,把請求放入workQueue中,池子裏的空閒線程就去從workQueue中取任務並處理

3)當workQueue放不下新入的任務時,新建線程入池,並處理請求,如果池子大小撐到了maximumPoolSize就用RejectedExecutionHandler來做拒絕處理

4)另外,當池子的線程數大於corePoolSize的時候,多餘的線程會等待keepAliveTime長的時間,如果無請求可處理就自行銷燬

內部結構如下所示:

從中可以發現ThreadPoolExecutor就是依靠BlockingQueue的阻塞機制來維持線程池,當池子裏的線程無事可幹的時候就通過workQueue.take()阻塞住。

其實可以通過Executes來學學幾種特殊的ThreadPoolExecutor是如何構建的。

[java] view plaincopy
  1. public static ExecutorService newFixedThreadPool(int nThreads) {  
  2.     return new ThreadPoolExecutor(nThreads, nThreads,  
  3.                                   0L, TimeUnit.MILLISECONDS,  
  4.                                   new LinkedBlockingQueue<Runnable>());  
  5. }  

newFixedThreadPool就是一個固定大小的ThreadPool

[java] view plaincopy
  1. public static ExecutorService newCachedThreadPool() {  
  2.     return new ThreadPoolExecutor(0, Integer.MAX_VALUE,  
  3.                                   60L, TimeUnit.SECONDS,  
  4.                                   new SynchronousQueue<Runnable>());  
  5. }  

newCachedThreadPool比較適合沒有固定大小並且比較快速就能完成的小任務,沒必要維持一個Pool,這比直接new Thread來處理的好處是能在60秒內重用已創建的線程。

其他類型的ThreadPool看看構建參數再結合上面所說的特性就大致知道它的特性

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