一 簡述
Executor核心的思想就是将請求處理任務的送出線程和任務的實際執行解耦開來。利用execute來傳遞一個具體執行的Runnable任務類,或者利用submit來傳遞一個Runnable任務類或Callable擷取任務傳回值的任務。
對于每次通過execute方法送出的任務執行順序如下:
1、會判斷目前池線程以及核心數目的大小,當池中目前的線程數小于核心線程數時,會建立新的線程。具體建立新線程流程如:擷取内置鎖,将任務添加到内部的BlockingQueue任務隊列中,再利用工廠方法産生一個執行該任務的線程,這個線程是非守護及優先級是NORM的線程。
2、當線程數大于等于核心線程數,且任務隊列未滿時,将任務放入任務隊列。
3、當線程數大于等于核心線程數,且任務隊列已滿,采用以下處理方式
若線程數小于最大線程數,建立線程
若線程數等于最大線程數,抛出異常,拒絕任務,進行飽和處理政策。
Executor任務執行架構類圖如下:
二 ThreadPoolExecutor線程池
一般線程池可以直接利用構造器來執行個體化一個ThreadPoolExecutor,也可以利用Executors工具類來建立一個線程池。也可以通過繼承擴充ThreadPoolExecutor來自定義一些ThreadPoolExecutor子類。
在利用Executors靜态生成ThreadPoolExecutor的時候,都會在内部執行個體化一個ThreadPoolExecutor。在ThreadPoolExecutor内部都是用BlockingQueue隊列來儲存送出的任務Runnable。
一個ThreadPoolExecutor需要考慮三個方面:
一個是線程池的大小,二個是任務隊列的大小,三個是飽和政策
常見的用法就是利用Executors的靜态工廠來建立。
标準的ThreadPoolExecutor構造方法如下:
1
2
3
4
5
6
7
<code>public</code> <code>ThreadPoolExecutor(</code><code>int</code> <code>corePoolSize,</code>
<code> </code><code>int</code> <code>maximumPoolSize,</code>
<code> </code><code>long</code> <code>keepAliveTime,</code>
<code> </code><code>TimeUnit unit,</code>
<code> </code><code>BlockingQueue<Runnable> workQueue,</code>
<code> </code><code>ThreadFactory threadFactory,</code>
<code> </code><code>RejectedExecutionHandler handler)</code>
ThreadPoolExecutor的幾個參數說明:
corePoolSize
核心線程數,核心線程會一直存活,即使沒有任務需要處理。當線程數小于核心線程數時,即使現有的線程空閑,線程池也會優先建立新線程來處理任務,而不是直接交給現有的線程處理。
核心線程在allowCoreThreadTimeout被設定為true時會逾時退出,預設情況下不會退出。
maxPoolSize
當線程數大于或等于核心線程,且任務隊列已滿時,線程池會建立新的線程,直到線程數量達到maxPoolSize。如果線程數已等于maxPoolSize,且任務隊列已滿,則已超出線程池的處理能力,線程池會拒絕處理任務而抛出異常。
keepAliveTime
當線程空閑時間達到keepAliveTime,該線程會退出,直到線程數量等于corePoolSize。如果allowCoreThreadTimeout設定為true,則所有線程均會退出直到線程數量為0。
allowCoreThreadTimeout
是否允許核心線程空閑退出,預設值為false。
queueCapacity
任務隊列容量。從maxPoolSize的描述上可以看出,任務隊列的容量會影響到線程的變化,是以任務隊列的長度也需要恰當的設定。
Executors靜态工廠建立線程池解釋
Executors.newCachedThreadPool();
這種會建立一個目标數目或核心數目為0,最大數目為Integer.MAX_VALUE逾時設定1分鐘,并且利用SynchronousQueue來存儲任務的ThreadPoolExecutor。SynchronousQueue是一種同步移交隊列,任務的生産者線程直接将任務移交給任務的消費者線程即工作線程。對于很大的線程池,可以利用SynchronousQueue避免任務的排隊。要想将一個元素放入該隊列,必須有另一個線程正在等待接收這個元素。當一個新的任務送出後,如果沒有線程在等待,且線程池的目前值大小小于最大值,一般ThreadPoolExecutor都會建立一個新的線程。否則就會調用飽和政策來處理。SynchronousQueue這種隊列一般用于當線程池無界或者很大的時候采用,目的就是更快的送出任務,充分利用線程池中的工作線程。
Executors.newFixedThreadPool(n);
這種會建立核心數目以及最大數目都是指定初始值的線程池,線程不會逾時也就是不會被回收,并且利用無界的(最大值是Integer.MAX_VALUE)的LinkedBlockingQueue來存儲任務的ThreadPoolExecutor。
Executors.newSingleThreadExecutor();
這種會建立核心數目以及最大數目都是1的線程池,線程不會逾時也就是不會被回收,并且利用無界的(最大值是Integer.MAX_VALUE)的LinkedBlockingQueue來存儲任務的ThreadPoolExecutor。
飽和政策解釋:
當有界隊列被填滿後,就需要考慮如何對于再次發送的請求處理。
ThreadPoolExecutor中可以通過setRejectedExecutionHandler設定飽和政策。
ThreadPoolExecutor中包含了四種飽和政策:
AbortPolicy, DiscardPolicy,DiscardOldestPolicy和CallerRunsPolicy
AbortPolicy,即中止政策,是預設的飽和政策,該政策将抛出未檢查的RejectedExecutionException。
DiscardPolicy,即抛棄政策,會丢棄隊列滿後請求的任務。
DiscardOldestPolicy,即抛棄最舊的政策,會抛棄下一個将要被執行的任務,然後嘗試重新送出新任務。
CallerRunsPolicy,即調用者政策,既不會抛棄任務,也不會抛出異常,而是将任務回退到調用者。它不會線上程池的某個線程執行新送出的任務,而是在一個調用execute的線程中執行該任務。
注意:
1、可以利用ArrayBlockingQueue,有界的LinkedBlockingQueue、PriorityBlockingQueue來設定存儲任務的隊列界限。
2、利用Executors靜态工廠方法建立ThreadPoolExecutor或者直接執行個體化ThreadPoolExecutor的對象,預設初始的時候線程并不會立即啟動,而是等到有任務送出時候才會啟動。當然可以調用prestartAllCoreThreads來啟動所有的核心線程。
3、在使用線程池中,當任務是互相獨立且類型基本上相同的時候,此時才可以設定線程池和工作隊列的界限。
本文轉自 zhao_xiao_long 51CTO部落格,原文連結:http://blog.51cto.com/computerdragon/1212442