Executor 、future學習(一)

Executor 

executor包括三個部分

1.任務,即工作單元,包括被執行的任務需要實現的接口:runnable貨callabe接口

2.任務的執行,把任務分配給多個線程執行的機制,包括Executor接口及繼承自Executor接口的ExecutorService接口

3.異步計算的結果,包括Future及實現了Future接口的FutureTask類

Executor

一個接口,定義了一個接受runnable對象的方法execute(Runnable command),接受一個runnable實例,用來執行一個任務,任務爲一個實現了Runnable接口的類,在Executor中,可以不顯示的創建線程executor.execute(new MyRunnable)來異步執行

ExecutorService

是一個比Executor更廣泛的子類接口,繼承Executor接口,提供生命週期管理方法:

shutDown():關閉當前service,釋放Executor的所有資源,觸發的動作是取消消息隊列中任務的執行,不再接受新的任務提交,同時把已經提交到隊列的任務執行完成

shutDownNow:它將會把尚未執行的任務不再執行,正在執行的任務,通過“線程中斷”(thread.interrupt),如果線程無法響應“中斷”,那麼將不會通過此方式被立即結束,該方法具有返回值,返回等待執行的任務列表List<Runnable>

isShutDown:程序是否關閉

isTerminated:是否已經結束,如果關閉後,所有的任務都執行完成,返回true,其他情況均爲false

awaitTermination(timeout):等待一段之間直到“任務全部結束”,如果超時就返回false

Future submit(callable/runnale):向Executor提交任務,並返回一個結果未定的Future

List<Future> invokeAll(Collection<Callable>):同步的方法,執行所有的任務列表,當所有任務都執行完成後,返回Future列表

T invokeAny(Collection<Callable>): 任務集合中,任何一個任務完成就返回

ScheduledExecutorService

設計爲了支持時間可控的任務執行:固定延時執行,週期延時執行,核心方法:

schedule(Callable<V> callable, long delay, TimeUnit unit)

schedule(Runnable command, long delay, TimeUnit unit)

這兩個方法是延時執行,只是傳入的參數不同

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

週期執行

scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

當前一個任務執行完成之後,延時delay,再開始執行第二個任務

 

框架示意圖

ScheduledThreadPool

創建一個大小無線的線程池,支持定時及週期性執行任務的需求

創建線程池要用到ThreadPoolExecutor

 

自定義線程池:ThreadPoolExecutor

 

corePoolSize:線程池中所保存的核心線程數,包括空閒線程

maximumPoolSize:池中允許最大的線程數

keepAliveTime:線程池中空閒線程能保存的最長時間

unit:持續時間的單位

workQueue:任務執行前保存任務的隊列,僅保存由execute方法提交的runnable任務,有四種阻塞隊列

(a)ArrayBlockingQueue

(b)LinkedBlockingQueue

(c)SynchronousQueue

(d)PriorityBlockingQueue

newFixedThreadPool使用了LinkedBlockingQueue,newCachedThreadPool使用了SynchronousQueue

threadFactory:新線程使用ThreadFactory創建,如果沒有指定,則使用Executors.defaultThreadFactory默認工廠

handler:飽和策略的句柄,當線程池包滿了,任務無法得到處理,需要使用飽和策略來處理無法完成的任務,有四種策略

(a)AbortPolicy:默認策略,直接拋出異常

(b)CallerRunPolicy:調用者所在線程來運行任務

(c)DiscardOldestPolicy:丟棄隊列中最老的任務,並執行當前任務

(d)DiscardPolicy:不處理,直接丟棄當前任務

可以自定義飽和策略,需要實現RejectExecutionHandler接口

 

向線程提交任務有兩種方法:execute和submit

execute用於提交沒有返回值的任務,所以無法判斷任務是否被執行過

 

 

submit用於提交需要返回值的對象,返回一個future對象,可以通過future對象判斷任務是否被線程執行,future.get()獲取返回的值,get方法會阻塞當前線程直道future對象被返回,也可以使用get(long timeout,TimeUnit unit)來實現由等待時間的獲取返回值,如果超市仍沒有返回值,那麼立刻返回,這時任務可能仍沒有執行

關閉線程池

遍歷線程池中的線程,逐個調用線程的interrupt來中斷線程,不響應中斷的線程可能無法停止

(a)shutDown:把線程的狀態置爲shutdown,然後中斷所有沒有正在執行任務的線程,已經在執行任務的線程繼續執行到任務完成

(b)shutDownNow:把當前線程池狀態置爲stop,嘗試停止所有的正在執行或暫停的線程,並返回等待執行任務的列表

調用之後,調用isShutDown返回true,當所有任務都關閉後,調用isTerminaed返回true

 

當通過execute方法將一個runnable任務添加到線程池中,處理順序:

1.如果線程池中的數量小於corePoolSize,即使線程池中有空閒的線程,也會創建一個新線程來執行新添加的任務

2.如果線程池中的數量大於等於corePoolSize,但是workQueue緩衝隊列未滿,則將新添加的任務放到workQueue中,線程池中有線程空閒出來後,依次將workQueue中的任務交給空閒的線程執行

3.如果線程池中的數量大於等於corePoolSize,而且workQueue緩衝隊列也滿了,但線程池中的數量小於maximunPoolSize,則會創建新的線程來處理被添加的任務

4.如果線程池中的數量等於maximumuPoolSize,使用RejectedExecutionHandler處理溢出線程

當有新的任務處理,先看線程池中的線程數量是否大於corePoolSize,再看緩衝隊列workQueue是否滿了,最後看線程池中的數量是否大於maximumuPoolSize

當線程池中的線程數量大於corePoolSize,如果裏面有線程的空閒時間超過了keepAliveTime,就將其移除線程池。

使用核心線程池+阻塞隊列+線程池的設計思路的優點

創建新的線程需要獲取全局鎖,爲了避免頻繁的獲取全局鎖,使用一個阻塞隊列來存儲任務,如果核心線程池中的線程執行任務的週期短,那麼執行完畢後立即從阻塞隊列中獲取任務,避免了重新創建線程,使線程的重複利用率提高,如果核心線程池中的執行週期長,使得阻塞隊列滿了還不斷的提交任務,這時再創建線程,使用一個核心線程池,一個線程池,是因爲核心線程池容量不能太大,不然阻塞隊列的緩存作用就降低了,但是如果線程池的數量太小,就限制了併發的線程數,降低了CPU的利用率

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