無限制創建線程的不足
- 線程生命週期的開銷非常高; 創建與銷燬過程中都極其耗費資源
- 資源消耗; 活躍的線程會消耗系統資源,尤其是內存。如果可運行的線程數量多於可用處理器的數量,那麼有些線程將閒置,大量的線程也會競爭CPU時鐘週期,這個時候再創建更多的線程反而會降低性能。
- 穩定性。 線程數量有限制,內存消耗過多,可能會拋出OutOfMemoryError
Executor框架的內部機制
基於生產者-消費者模式,提交任務的操作相當於生產者(生成待完成的工作單元),執行任務的線程則相當於消費者(執行完成這些工作單元)。
使用線程池的優勢
- 通過重用現有的線程而不是創建新線程,可以在處理多個請求時分攤線程創建和銷燬過程中產生的巨大開銷。
- 當請求到達時,工作線程通常已經存在,因此不會由於等待創建線程而延遲任務的執行,從而提高了響應性。
- 通過適當調整足夠多的線程以便使處理器保持忙碌狀態。
- 同時還可以防止過多的線程相互競爭資源而使應用程序耗盡內存或者失敗。
使用線程池限制線程數量並不能完全解決資源耗盡的問題
儘管服務器不會因爲創建過多的線程而失敗,但在足夠長的時間內,如果任務到達的速度總是超過任務執行的速度,那麼服務器仍有可能(只是更不易)耗盡內存,因爲等待執行的Runnable隊列將不斷增長,可以通過使用一個有界隊列在Executor框架內部解決這個問題。
ExecutorService生命週期:運行、關閉和已終止
- ExecutorService在初使化創建時處於運行狀態。
- Shutdown方法將執行平緩的關閉過程:不再接受新的任務,同時等待已經提交的任務執行完成——包括那些還未開始執行的任務。
- ShutdownNow方法將執行粗暴的關閉過程:它嘗試取消所有運行中的任務,並且不再啓動隊列中尚未開始執行的任務。
CompletionService併發計算並批量獲取結果
它是在線程池基礎上進行併發計算的進一步抽象,將Executor和BlockingQueue的功能融合在一起。你可以將Callable任務提交給它來執行,然後使用類似於隊列操作的take和poll等方法來獲得已完成的結果。而這些結果在完成時將被封裝爲Future。
一個更簡單的實現方法是使用Executor的invokeAll方法,提交一組任務,並返回一組Future以獲取結果。
爲任務設置時限
- 要實現這個功能,可以由任務本身來管理它的限定時間,並且在超時後中止執行或取消任務。
- 可再次使用Future,如果一個限時的get方法拋出了TimeoutException,那麼可以通過Future來取消任務。