1. 程式人生 > >執行緒池executor,executorService,ThreadPoolExecutor

執行緒池executor,executorService,ThreadPoolExecutor

Executor是一個介面,他是Executor框架的基礎,它將任務的提交與任務的執行分離。 

Executor介面中之定義了一個方法execute(Runnable command),該方法接收一個Runable例項,它用來執行一個任務,任務即一個實現了Runnable介面的類。

ExecutorService介面繼承自Executor介面,它提供了更豐富的實現多執行緒的方法,一般用該介面來實現和管理多執行緒。比如,ExecutorService提供了關閉自己的方法,以及可為跟蹤一個或多個非同步任務執行狀況而生成 Future 的方法。 可以呼叫ExecutorService的shutdown()方法來平滑地關閉 ExecutorService,呼叫該方法後,將導致ExecutorService停止接受任何新的任務且等待已經提交的任務執行完成(已經提交的任務會分兩類:一類是已經在執行的,另一類是還沒有開始執行的),當所有已經提交的任務執行完畢後將會關閉。

ExecutorService的生命週期包括三種狀態:執行、關閉、終止。建立後便進入執行狀態,當呼叫了shutdown()方法時,便進入關閉狀態,此時意味著ExecutorService不再接受新的任務,但它還在執行已經提交了的任務,當素有已經提交了的任務執行完後,便到達終止狀態。如果不呼叫shutdown()方法,ExecutorService會一直處在執行狀態,不斷接收新的任務,執行新的任務,伺服器端一般不需要關閉它,保持一直執行即可

Executors提供了一系列工廠方法用於創先執行緒池,返回的執行緒池都實現了ExecutorService介面

SingleThreadExecutor是使用單個worker執行緒的Executor。特點是使用單個工作執行緒執行任務。SingleThreadExecutor的corePoolSize和maxiumPoolSize都被設定1

我們可以通過呼叫執行緒池的shutdown或shutdownNow方法來關閉執行緒池,但是它們的實現原理不同,shutdown的原理是隻是將執行緒池的狀態設定成SHUTDOWN狀態,然後中斷所有沒有正在執行任務的執行緒。shutdownNow的原理是遍歷執行緒池中的工作執行緒,然後逐個呼叫執行緒的interrupt方法來中斷執行緒,所以無法響應中斷的任務可能永遠無法終止。shutdownNow會首先將執行緒池的狀態設定成STOP,然後嘗試停止所有的正在執行或暫停任務的執行緒,並返回等待執行任務的列表。只要呼叫了這兩個關閉方法的其中一個,isShutdown方法就會返回true。當所有的任務都已關閉後,才表示執行緒池關閉成功,這時呼叫isTerminaed方法會返回true。至於我們應該呼叫哪一種方法來關閉執行緒池,應該由提交到執行緒池的任務特性決定,通常呼叫shutdown來關閉執行緒池,如果任務不一定要執行完,則可以呼叫shutdownNow。

執行緒執行過程:
1.如果當前工作中的執行緒數量少於corePool的數量,就建立新的執行緒來執行任務。
2.當執行緒池的工作中的執行緒數量達到了corePool,則將任務加入LinkedBlockingQueue。
3.執行緒執行完1中的任務後會從佇列中去任務。
注意LinkedBlockingQueue是無界佇列,所以可以一直新增新任務到執行緒池。
當一個任務通過execute(Runnable)方法欲新增到執行緒池時:
l  如果此時執行緒池中的數量小於corePoolSize,即使執行緒池中的執行緒都處於空閒狀態,也要建立新的執行緒來處理被新增的任務。
2  如果此時執行緒池中的數量等於 corePoolSize,但是緩衝佇列 workQueue未滿,那麼任務被放入緩衝佇列。
3  如果此時執行緒池中的數量大於corePoolSize,緩衝佇列workQueue滿,並且執行緒池中的數量小於maximumPoolSize,建新的執行緒來處理被新增的任務。
4  如果此時執行緒池中的數量大於corePoolSize,緩衝佇列workQueue滿,並且執行緒池中的數量等於maximumPoolSize,那麼通過 handler所指定的策略來處理此任務。也就是:處理任務的優先順序為:核心執行緒corePoolSize、任務佇列workQueue、最大執行緒maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。  
當執行緒池中的執行緒數量大於 corePoolSize時,如果某執行緒空閒時間超過keepAliveTime,執行緒將被終止。這樣,執行緒池可以動態的調整池中的執行緒數
建立一個執行緒池需要輸入幾個引數:
corePoolSize(執行緒池的基本大小):當提交一個任務到執行緒池時,執行緒池會建立一個執行緒來執行任務,即使其他空閒的基本執行緒能夠執行新任務也會建立執行緒,等到需要執行的任務數大於執行緒池基本大小時就不再建立。如果呼叫了執行緒池的prestartAllCoreThreads方法,執行緒池會提前建立並啟動所有基本執行緒。
runnableTaskQueue(任務佇列):用於儲存等待執行的任務的阻塞佇列。可以選擇4種阻塞佇列:
ArrayBlockingQueue: 是一個基於陣列結構的有界阻塞佇列,此佇列按 FIFO(先進先出)原則對元素進行排序。
LinkedBlockingQueue: 一個基於連結串列結構的阻塞佇列,此佇列按FIFO (先進先出) 排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個佇列。
SynchronousQueue: 一個不儲存元素的阻塞佇列。每個插入操作必須等到另一個執行緒呼叫移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個佇列。
PriorityBlockingQueue: 一個具有優先順序得無限阻塞佇列。
maximumPoolSize(執行緒池最大大小):執行緒池允許建立的最大執行緒數。如果佇列滿了,並且已建立的執行緒數小於最大執行緒數,則執行緒池會再建立新的執行緒執行任務。值得注意的是如果使用了無界的任務佇列這個引數就沒什麼效果。
ThreadFactory:用於設定建立執行緒的工廠,可以通過執行緒工廠給每個創建出來的執行緒設定更有意義的名字,Debug和定位問題時非常又幫助。
RejectedExecutionHandler(飽和策略,也即拒絕策略):當佇列和執行緒池都滿了,說明執行緒池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。這個策略預設情況下是AbortPolicy(直接丟擲異常),表示無法處理新任務時丟擲異常。以下是JDK1.5提供的四種策略:
1.  CallerRunsPolicy:只用呼叫者所線上程來執行任務。
2.  DiscardOldestPolicy:丟棄佇列裡最近的一個任務,並執行當前任務。
3.  DiscardPolicy:不處理,丟棄掉。
4.  當然也可以根據應用場景需要來實現RejectedExecutionHandler介面自定義策略。如記錄日誌或持久化不能處理的任務。
keepAliveTime(執行緒活動保持時間):執行緒池的工作執行緒空閒後,保持存活的時間。所以如果任務很多,並且每個任務執行的時間比較短,可以調大這個時間,提高執行緒的利用率。
TimeUnit(執行緒活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
ThreadPoolExecutor類實現了ExecutorService介面和Executor介面,可以設定執行緒池corePoolSize,最大執行緒池大小,AliveTime,拒絕策略等。
corePoolSize: 執行緒池維護執行緒的最少數量
maximumPoolSize:執行緒池維護執行緒的最大數量
keepAliveTime: 執行緒池維護執行緒所允許的空閒時間
unit: 執行緒池維護執行緒所允許的空閒時間的單位
workQueue: 執行緒池所使用的緩衝佇列
handler: 執行緒池對拒絕任務的處理策略