一、Executor 框架的排程模型
1.1 目的
在平時的開發中,我們經常需要將一些耗時的任務放到非同步執行緒當中進行處理,而執行緒的建立和銷燬都是需要耗費資源的,設計Executor
框架的目的就是為了在上層能夠對這些非同步任務進行有效地管理和排程。
1.2 排程模型
我們可以把Executor
框架想象成一個公司,開發者所需要完成的任務則是一個訂單,那麼任務的執行可以分解為下面這個過程:
- 開發者將訂單提交給公司
- 公司把訂單指派給對應的員工
- 公司員工將訂單交給工廠
- 工廠員工執行訂單
訂單、公司、公司員工、工廠和工廠員工這幾個概念的對映如下圖所示:
Executor
框架對於內部執行緒的排程過程,就可以理解為公司對於員工的管理機制,而這一過程對於開發者是不可見的。
二、Executor 框架
整個Executor
的框架主要由三個部分組成:
FutureTask
:任務ThreadPoolExecutor
:常規任務管理者ScheduledThreadPoolExecutor
:週期任務管理者
下面,我們就分這三個部分來簡要介紹一下涉及到的相關類。
2.1 任務
與任務相關的類的繼承關係如下圖所示:
當我們向ThreadPoolExecutor
或者ScheduledThreadPoolExecutor
提交任務時,有以下四種方式:
public void execute(Runnable command)
public Future<?> submit(Runnable task)
public <T> Future<T> submit(Runnable task, T result)
public <T> Future<T> submit(Callable<T> task)
複製程式碼
- 當通過
execute
方法提交一個Runnable
的實現類時,不會得到返回的結果 - 當通過
submit
方法提交一個Runnable
或者Callable
的實現類時,會返回一個Future
的實現類,在目前JDK
的實現當中: - 提交到
ThreadPoolExecutor
,返回FutureTask
- 提交到
ScheduledThreadPoolExecutor
,返回ScheduledFutureTask
Future
介面所提供的方法提供了下面幾個功能:
- 通過
isCancelled()
和isDone()
方法來獲取任務當前的狀態 - 通過
cancel()
來取消任務的執行 - 通過
get()
方法來阻塞地獲取任務的執行結果
2.2 常規任務管理者
與常規任務執行者相關的類的繼承關係如下:
ThreadPoolExecutor
通常作為常規任務的管理者,根據執行緒池的大小、工作佇列的區別,可以實現不同的任務管理策略。
一般情況下,通常使用工廠類Executors
來建立不同型別ThreadPoolExecutor
:
FixedThreadPool
:為了滿足限制當前執行緒數量的場景,適用於負載比較重的伺服器。SingleThreadPoolExecutor
:適用於需要保證順序地執行各個任務,在任意時間點,不會有多個活動的應用場景。CacheThreadPool
:大小無界的執行緒池,適用於執行很多的短期非同步任務的小程式或者是負載較輕的伺服器。
2.3 週期任務管理者
與週期任務有關的類的繼承關係如下:
ScheduledThreadPoolExecutor
相比於ThreadPoolExecutor
,它主要用來在給定的延遲之後執行任務,或者定期執行任務。和ThreadPoolExecutor
類似,我們也可以通過Executors
類來獲得它不同的實現:
ScheduledThreadPoolExecutor
:適用於需要多個後臺執行緒執行週期任務,同時為了滿足資源管理的需求而需要限制後臺執行緒的數量的應用場景。SingleThreadScheduledExecutor
:適用於需要單個後臺執行緒執行週期任務,同時需要保證順序地執行各個任務的應用場景。
三、小結
通過Executor
框架,就可以把工作單元與執行機制進行分離,開發者只需要把需要執行的任務通過Runnable
或者Callable
封裝成為執行單元,具體的執行機制則由Executor
的實現類去處理,免去了開發者對於任務的管理成本。
這篇文章,主要是對Executor
框架進行了一個簡要的介紹,之後我們會深入到第二節討論的三個部分當中,分析Executor
內部對於執行緒管理的實現機制。