2018.10.29
前言
併發問題是項目開發中的常見問題,Java的java.util.concurrent
包提供了許多可靠、實用的工具給開發者。粗略地看了文檔和代碼,決定寫下這篇簡介,但是出於時間成本的考慮,本文未涵蓋代碼案例及測試分析等內容。
萬惡之源的Executor
接口
下圖是Executor
接口及其相關接口、類的UML圖1。Executor
作爲最頂層的接口,顧名思義就是執行某個可執行命令(Runnable
線程)的執行器。
ExecutorService
接口則是在Executor
的基礎上,提供這個可執行命令的管理方法,主要是啓停操作。到此,ExecutorService
接口滿足了對線程生命週期基本的管理需求,調度相關的需求由ScheduledExecutorService
接口來補充。
AbstractExecutorService
抽象類是ExecutorService
的默認實現。子類ForkJoinPool
的特點是支持任務竊取機制(Work-Stealing),對於那些大量產生子任務的任務,該子類採用的任務竊取機制會有助於提高整體的性能表現。而本文的主角ThreadPoolExecutor
類,作爲一個線程池則適用於大量異步任務執行的場景,具體原因有待實驗驗證。
Executors
血汗工廠
使用Java的Executors
工廠方法創建ExecutorService
實例,可以減少開發者對參數的理解成本和選型成本。常用的有如下幾個:
newSingleThreadExecutor
:是一個只有一個線程的線程池,使用上,就是一個可自主管控的線程,可直接控制啓停、判斷狀態等。newFixedThreadPool
:固定大小的線程池,當需要控制併發度或在併發度不高的場景下,就可以採用該線程池。newCachedThreadPool
:緩存線程池,這裏的緩存是指當線程執行完任務之後,還會留在線程池中,對於短壽異步任務較多的場景,這個線程池能帶來可觀的性能提升;而且線程池大小不受限,最大能包含Integer.MAX_VALUE
個線程。
以上三個線程池本質上都是ThreadPoolExecutor
,只是配置不同。而還有其它線程池,如基於ForkJoinPool
的newWorkStealingPool
,不作過多介紹,讀者可按需深入瞭解。