FutureTask是一個可取消的異步計算框架。其中內部用的是state來記錄任務的執行狀態。
java
如上所示FutrueTask內部封裝了以上的Object。全部經過調用Futuretask執行的任務都會在齊內部包裝成一個callable來執行。node
以上貼出的兩個FutureTask的構造函數,要麼直接構造一個實現了callable接口的對象,要麼傳入一個實現Runnable接口的對象,在其內部將Runnable轉換爲callable。多線程
接下來看看FutureTask的核心方法
框架
可經過將FutureTask放入一個線程,或者將其放入線程池中實現調用。其中set()和setException()會喚醒存在waiters中的node,告訴他們計算已經完成,或者計算中拋出了異常。
在set()、setException()和cancel()方法的末尾都會調用finishCompletion()方法來釋放存在waiters中的線程,在該方法中還有一個done()方法,用來讓子類實現,作一些異步任務完成以後的事情。
看看cancel()方法
異步
須要注意的是任務只有在state == NEW的時候才能被取消。函數
FutureTask可經過get()調用獲得計算的結果,若是計算還沒完成,該方法會阻塞,也可響應中斷。產生阻塞的時候會將線程wrap成node加入到waiters中。下面看看get中調用的awaitDone(boolean timed, long nanos)方法
this
awaitDone代碼中採起死循環的方式:
檢查是否響應中斷,如果,則移除該node,拋出中斷異常。spa
if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException(); }
若此時已經結束,返回此時的狀態值。線程
int s = state; if (s > COMPLETING) { if (q != null) q.thread = null; return s; }
若判斷爲如下狀況則暫時讓出cpu時間,稍後執行,由於COMPLETING是一個瞬時的狀態,說明這個時候計算結果已經立刻要被set了,或者也多是拋出了異常。code
else if (s == COMPLETING) // cannot time out yet Thread.yield();
若判斷爲如下狀況則新建一個node,該node包裝了當前的線程。
else if (q == null) q = new WaitNode()
若判斷爲如下狀況則將node加入到waiters中
else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);
接下來最後的兩個判斷都是park這個線程,只是有時間的區分。
利用FutureTask和ExecutorService,能夠用多線程的方式提交計算任務,主線程繼續執行其餘任務,當主線程須要子線程的計算結果時,在異步獲取子線程的執行結果。