天天看點

關于Future

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事件。