1 為什麼需要Callable和Future
Runnable沒有傳回值,也不抛異常,這樣主線程不能知道子線程的執行結果。
為了解決這個問題就有了Callable和Future。Callable提供的call方法傳回一個結果,然後把這個結果交給Future,主線程通過Future就能夠擷取子線程執行的結果了。
Callable給子線程提供入參,Future提供子線程的傳回值。FutureTask合二為一,它把Callable作為成員儲存起來,而它本身就是一個Future。
2 什麼是Future
Future被用來表示一個異步計算的未來結果。
Future提供了5個接口來查詢異步任務的計算結果:
isDone:是否執行完了。
兩個get,一個阻塞,一個計時阻塞。
cancel,取消任務的執行。
isCanceled,查詢任務是否取消了執行。
3 Future有什麼用
3.1 異步調用和并發
耗時的計算适用于異步和Future。
3.2 Future異步計算的使用舉例
計算密集的任務;
處理大的資料結構;
遠端方法調用:下載下傳檔案、web服務等
4 Future是如何實作的
Future能實作本質上是因為java的對象都是放在堆上的。FutureTask是在主線程中建立的對象,将之交給其它線程或者線程池去執行,線程執行完了之後,有一個傳回值,将該傳回值放在FutureTask的成員outcome上。然後,FutureTask再提供get函數來給主線程擷取這個執行的結果。
4.1 FutureTask get實作的原理
第一,維護一個狀态機,使用者調用get之後,根據不同的執行狀态,傳回不同的值。
第二,如果任務還沒有執行完,就把該線程放入等待隊列,并且調用LockSupport.park()函數讓阻塞該線程,這樣get就阻塞了。
第三,在任務執行完了之後,會把這些等待隊列中的線程踢出,并且調用LockSupport.unpark()函數解除阻塞,線程被喚醒。
5 Runnable和Callable比較
5.1 相同點
Runnable和Callable都提供線程的執行體。
5.2 Runable不提供傳回值,也不抛異常。Callable提供傳回值,可能會抛一個異常
比如FutureTask實作了Callable接口,call方法執行了之後将結果放在FutureTask的outcome成員中。
調用get的時候,如果執行體正常執行則傳回該outcome,如果不正常執行就傳回Exception。
6 Callable的使用場景
6.1 和Thread一起使用
需要一個中間人FutureTask,該類實作了Runnable和Future接口。因為實作了Runnable接口,是以可以作為參數傳給Thread,建立一個新的thread。
FutureTask也可以作為參數傳給線程池。
7 總結一下
Callable和Future一起使用來擷取異步執行的結果。Callable作為入參,提供線程的執行體和該異步計算的傳回值。Future作為異步計算的傳回結果。
8 grpc中對Future的使用,grpc是如何通過Future來實作對異步調用結果的擷取的?
異步調用時,伺服器端調用執行完了,執行的結果是如何交給用戶端的?
io是netty實作的,伺服器端的調用執行之後,通過通道告知用戶端,然後用戶端就調用相應的listener。netty的伺服器端和用戶端都是有多路複用器的。用于監聽各個IO事件。