Future 和 FutureTask 原始碼詳解

2021-09-24 08:04:18 字數 3772 閱讀 1600

future 就像它字面上的意思差不多就是「未來」的意思。在實際開發場景中有時需要非同步呼叫一些介面或函式,但是這些介面或函式都不會立即返回結果且該結果不會影響後續程式的執行,這個時候使用future就非常的適合,舉例來說:

如查乙個資料集合,第一頁至第一百頁,返回總頁數的總結集,然後匯出。一次需要limit 0 10000,這樣,乙個sql查詢出非常慢。但用100個執行緒,乙個執行緒只查limit0 10 就非常快了, 利用多執行緒的特性,返回多個集合,在順序合併成總集合。

future 是乙個介面而 futuretask 是它的常用實現類。

futuretask(callable callable)

public futuretask(callablecallable) 

複製**

futuretask(runnable runnable, v result)

public futuretask(runnable runnable, v result) 

複製**

該方法最終是通過 runnableadapter 來生成的 callable

static final class runnableadapterimplements callable

public t call

() }

複製**

這裡實現了 callable 介面

futuretask> future = new futuretask<>(new callable>() 

new thread(future).start();

複製**

/** 

* 狀態之間的轉換如下:

* possible state transitions:

* new -> completing -> normal

* new -> completing -> exceptional

* new -> cancelled

* new -> interrupting -> interrupted

*/private volatile int state;

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; // 已中斷

複製**

下面開始詳細講解 run 方法:

public void run

() catch (throwable ex)

if (ran)

set(result); // 呼叫成功則執行 set 講執行結果設定到返回結果中

}} finally

}複製**

這裡需要講一下 set(result) 這個方法

protected void set(v v) 

}複製**

這裡就不講 setexception(ex) 這個方法了,因為它和 set 方法幾乎一致。但是在這裡我們看到了乙個 finishcompletion 方法,那這個方法具體是怎麼執行的呢?下面就來對它進行乙個細緻的分析:

private void finishcompletion

() waitnode next = q.next;

if (next == null)

break;

q.next = null; // unlink to help gc

q = next;

}break;}}

done();

callable = null; // to reduce footprint

}複製**

public v get() throws interruptedexception, executionexception 

複製**

等待方法 awaitdone

private int awaitdone(boolean timed, long nanos)

throws interruptedexception

int s = state;

if (s > completing)

else

if (s == completing) // cannot time out yet

thread.yield(); // 使當前執行緒從執行狀態(執行狀態)變為可執行態(就緒狀態)。說人話就是隔一會執行。

else

if (q == null)

q = new waitnode();

else

if (!queued)

queued = unsafe.compareandswapobject(this, waitersoffset,

q.next = waiters, q); // 設定等待節點

else

if (timed)

locksupport.parknanos(this, nanos);

}else

locksupport.park(this);}}

複製**

設定返回值 report 方法

private v report(int s) throws executionexception 

複製**

這裡主要講了 run 方法和 get 方法。在 run 方法中是通過拿取和改變 state 的狀態來判斷和執行具體**。在 run 方法中只要不出現異常,一開始 state 都是 new 。在是 new 的情況下才會去 runner 設定為當前執行緒。後續才會去呼叫具體的 call 方法,不管是丟擲異常或者是拿到正確的執行結果都會設定到返回值當中。在設定返回值,又會去更改 state 的狀態,之後就會對等待的執行緒依次進行喚醒(這裡可能也沒有等待執行緒,因為等待執行緒的出現是因為在非同步執行的**還未執行完拿到結果,這邊就呼叫了 get 方法。此時就會出現等待執行緒),喚醒的執行緒就能拿到結果了。這裡的 get 方法中的整體邏輯就相對來說要簡單一些了,在 get 方法中首先通過 state 判斷是否需要等待,若要等待就呼叫 awaitdone 方法去加入等待(這裡會有邏輯去判斷是否取消、中斷、超時)。最後在呼叫 report 方法返回結果值(這裡有邏輯會對異常進行乙個處理)。其實這裡都是通過改變和獲取 state 的狀態來對後續的操作進行乙個判斷。

Callable和future介面詳解

runnbale封裝乙個非同步執行的任務,可以把它想象成乙個沒有任何引數和返回值的非同步方法。callable和runnable相似,但是它有返回值。callable介面是引數化的型別,只有乙個方法call public inte ce callable catch runtimeexception...

Callable 和 Future介面 學習

callable是類似於runnable的介面,實現callable介面的類和實現runnable的類都是可被其它執行緒執行的任務。callable和runnable有幾點不同 1 callable規定的方法是call 而runnable規定的方法是run 2 callable的任務執行後可返回值,...

程式設計結構 Promise和Future

非阻塞模型中promise,future 和 callback一些比較常用的模型 future表示乙個可能還沒有實際完成的非同步任務結果 實際在程式設計中,應用future資料結構的時候,你得到並不是乙個真實結果 而是乙個futuredata 真實的結果可能還沒有處理完成。當然你可以針對這個結果新增...