原創文章&經驗總結&從校招到 A 廠一路陽光一路滄桑
詳情請戳www.codercc.com
1.FutureTask 簡介
在 Executors 框架體系中,FutureTask 用來表示可獲取結果的非同步任務。FutureTask 實現了 Future 介面,FutureTask 提供了啟動和取消非同步任務,查詢非同步任務是否計算結束以及獲取最終的非同步任務的結果的一些常用的方法。通過get()
方法來獲取非同步任務的結果,但是會阻塞當前執行緒直至非同步任務執行結束。一旦任務執行結束,任務不能重新啟動或取消,除非呼叫runAndReset()
方法。在 FutureTask 的原始碼中為其定義了這些狀態:
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
複製程式碼
另外,在《java 併發程式設計的藝術》一書,作者根據 FutureTask.run()方法的執行的時機,FutureTask 分為了 3 種狀態:
未啟動。FutureTask.run()方法還沒有被執行之前,FutureTask 處於未啟動狀態。當建立一個 FutureTask,還沒有執行 FutureTask.run()方法之前,FutureTask 處於未啟動狀態。 已啟動。FutureTask.run()方法被執行的過程中,FutureTask 處於已啟動狀態。 已完成。FutureTask.run()方法執行結束,或者呼叫 FutureTask.cancel(...)方法取消任務,或者在執行任務期間丟擲異常,這些情況都稱之為 FutureTask 的已完成狀態。
下圖總結了 FutureTask 的狀態變化的過程:
由於 FutureTask 具有這三種狀態,因此執行 FutureTask 的 get 方法和 cancel 方法,當前處於不同的狀態對應的結果也是大不相同。這裡對 get 方法和 cancel 方法做個總結:
get 方法
當 FutureTask 處於未啟動或已啟動狀態時,執行 FutureTask.get()方法將導致呼叫執行緒阻塞。如果 FutureTask 處於已完成狀態,呼叫 FutureTask.get()方法將導致呼叫執行緒立即返回結果或者丟擲異常
cancel 方法
當 FutureTask 處於未啟動狀態時,執行 FutureTask.cancel()方法將此任務永遠不會執行;
當 FutureTask 處於已啟動狀態時,執行 FutureTask.cancel(true)方法將以中斷執行緒的方式來阻止任務繼續進行,如果執行 FutureTask.cancel(false)將不會對正在執行任務的執行緒有任何影響;
當FutureTask處於已完成狀態時,執行 FutureTask.cancel(...)方法將返回 false。
對 Future 的 get()方法和 cancel()方法用下圖進行總結
2. FutureTask 的基本使用
FutureTask 除了實現 Future 介面外,還實現了 Runnable 介面。因此,FutureTask 可以交給 Executor 執行,也可以由呼叫的執行緒直接執行(FutureTask.run())。另外,FutureTask 的獲取也可以通過 ExecutorService.submit()方法返回一個 FutureTask 物件,然後在通過 FutureTask.get()或者 FutureTask.cancel 方法。
**應用場景:**當一個執行緒需要等待另一個執行緒把某個任務執行完後它才能繼續執行,此時可以使用 FutureTask。假設有多個執行緒執行若干任務,每個任務最多隻能被執行一次。當多個執行緒試圖執行同一個任務時,只允許一個執行緒執行任務,其他執行緒需要等待這個任務執行完後才能繼續執行。
參考文獻
《java 併發程式設計的藝術》