Java裡麵線程池的頂級介面是Executor,但是嚴格意義上講Executor並不是一個線程池,而只是一個執行線程的工具。真正的線程池介面是ExecutorService。
下面這張圖完整描述了線程池的類體繫結構。
首先Executor的execute方法只是執行一個Runnable的任務,當然了從某種角度上將最後的實作類別也是線上程中啟動此任務的。根據線程池的執行策略最後這個任務可能在新的線程中執行,或者線程池中的某個線程,甚至是調用者線程中執行(相當於直接運行Runnable的run方法)。這點在後面會詳細說明。
ExecutorService在Executor的基礎上增加了一些方法,其中有兩個核心的方法:
- Future<?> submit(Runnable task)
- <T> Future<T> submit(Callable<T> task)
這兩個方法都是向線程池中提交任務,它們的區別在於Runnable在執行完畢後沒有結果,Callable執行完畢後有一個結果。這在多個線程中傳遞狀態和結果是非常有用的。另外他們的相同點在雩都返回一個Future對象。Future對象可以阻塞線程直到運行完畢(擷取結果,如果有的話),也可以取消任務執行,當然也能夠檢測任務是否被取消或者是否執行完畢。
在沒有Future之前我們檢測一個線程是否執行完畢通常使用Thread.join()或者用一個死迴圈加狀態位來描述線程執行完畢。現在有了更好的方法能夠阻塞線程,檢測任務執行完畢甚至取消執行中或者未開始執行的任務。
ScheduledExecutorService描述的功能和Timer/TimerTask類似,解決那些需要任務重複執行的問題。這包括延遲時間一次性執行、延遲時間周期性執行以及固定延遲時間周期性執行等。當然了繼承ExecutorService的ScheduledExecutorService擁有ExecutorService的全部特性。
ThreadPoolExecutor是ExecutorService的預設實現,其中的配置、策略也是比較複雜的,在後面的章節中會有詳細的分析。
ScheduledThreadPoolExecutor是繼承ThreadPoolExecutor的ScheduledExecutorService介面實現,週期性任務調度的類實現,在後面的章節中會有詳細的分析。
這裡需要稍微提一下的是CompletionService介面,它是用於描述順序擷取執行結果的一個線程池封裝器。它依賴一個具體的線程池調度,但是能夠根據任務的執行先後順序得到執行結果,這在某些情況下可能提高並發效率。
要配置一個線程池是比較複雜的,尤其是對於線程池的原理不是很清楚的情況下,很有可能配置的線程池不是較優的,因此在Executors類裡面提供了一些靜態工廠,產生一些常用的線程池。
- newSingleThreadExecutor:建立一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當於單線程串列執行所有任務。如果這個唯一的線程因為異常結束,那麼會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行。
- newFixedThreadPool:建立固定大小的線程池。每次提交一個任務就建立一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那麼線程池會補充一個新線程。
- newCachedThreadPool:建立一個可快取的線程池。如果線程池的大小超過了處理任務所需要的線程,那麼就會回收部分空閑(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴於作業系統(或者說JVM)能夠建立的最大線程大小。
- newScheduledThreadPool:建立一個大小無限的線程池。此線程池支援定時以及周期性執行任務的需求。
- newSingleThreadExecutor:建立一個單線程的線程池。此線程池支援定時以及周期性執行任務的需求。
在詳細講解ThreadPoolExecutor的時候會具體討論上述參數配置後的意義和原理。
線程池是一個複雜的任務調度工具,因此它涉及到任務、線程池等的生命週期問題,在下一節中來探討下這個問題。
本文轉自www.35java.com