ThreadPoolExecutor源碼中的適配器模式
- 2019 年 11 月 3 日
- 筆記
什麼是適配器模式
網上已有很多的教程,不細講了。可以參考:五分鐘了解設計模式(3)—適配器模式
在適配器模式中,一定要識別清楚,Target Adaptee Adapter分別是哪些類或介面,這樣才能知道是誰轉成誰。
Target: 最終給上下文調用的類
Adaptee: 被適配的類,即需要轉成Target
Adapter: 將Target和Adaptee連接起來,起轉換作用
ThreadPoolExecutor中submit方法用到的適配器模式
ThreadPoolExecutor類提供了submit方法,共有3個重載。這三個方法最終調用到的是execute(Runnable r) 方法,返回一個Future類型的對象(具體為FutureTask類型),相比直接調用execute(Runnable r)方法,調用方可以獲得任務執行的結果。三個submit方法, 都使用了適配器模式,才能將順利調用execute(Runnable r)方法。
- 先看看public
Future submit(Callable task)
在這個方法中,Target是Runnable(因為execute方法的參數是Runnable類型),Adaptee是Callable。JDK使用了FutureTask類作為Adapter. FutureTask類的繼承關係如下
實現了Runnable,可以傳參給execute方法;實現了Future,可以返回給調用方。
FutureTask作為Adapter,採用的是「類適配器方式」,持有一個Callable(即Adaptee)。
-
再看看public
Future submit(Runnable task, T result)
同樣是包裝成FutureTask類型,那麼只要將Runnable轉成FutureTask就可以了。上面說到FutureTask也是實現了Runnable,那為什麼還要轉換呢?因為FutureTask還實現了Future介面,功能上比Runnable更強大,同時要返回給調用方,提供運行結果。
當前我們有一個Runnable和表示結果的參數,需要適配成FutureTask。前面我們已經知道,FutureTask起到Adapter的作用,它持有一個Callable成員變數。如果沒有上面的分析,那麼FutureTask可以改為持有Runnable,但現在它已經是持有Callable成員變數了,所以,還要再做一次適配,將Runnable適配成Callable.
在這個例子中,Target是Callable,Adaptee是Runnable,Adapter是RunnableAdapter。
RunnableAdapter使用「類適配器方式」
-
最後一個public Future<?> submit(Runnable task)
與上一個方法類似,只不過是運行結果為null.
總結
在ThreadPoolExecutor的三個submit方法中,都使用了適配器模式,都使用了其中的「類適配器方式」。
submit方法都返回FutureTask,該類型可以得到運行結果。
submit方法都調用了execute(Runnable r)方法執行任務,傳入的具體類型為FutureTask。因此,Target是Runnable,Adapter是FutureTask,Adaptee則是不同的傳入參數。
FutureTask的實現方式是持有一個Callable類型的成員變數,因此,對於傳入參數為Callable的情況,直接賦值,對於傳入參數為Runnable的情況,需要再做一次適配,將Runnable適配成Callable. 在這個轉換過程中,Target是Callable,Adaptee是Runnable,Adapter是Adapter是RunnableAdapter。