JUC - FutureTask 源碼分析

簡介

FutureTask,可取消的異步計算。利用開始和取消計算的方法、查詢計算是否完成的方法和獲取計算結果的方法,此類提供了對 Future 的基本實現。僅在計算完成時才能獲取結果;如果計算尚未完成,則阻塞 get 方法。一旦計算完成,就不能再重新開始或取消計算。可使用 FutureTask 包裝 Callable 或 Runnable 對象。因爲 FutureTask 實現了 Runnable,所以可將 FutureTask 提交給 Executor 執行。

源碼分析

FutureTask類繼承關係

FutureTask類實現了RunnableFuture接口,RunnableFuture接口繼承自Future接口和Runnable接口,整合了一下Future接口和Runnable接口。
其中的方法在FutureTask中做了具體的實現。

  • Future接口表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並獲取計算的結果。計算完成後只能使用 get 方法來獲取結果,如有必要,計算完成前可以阻塞此方法。取消則由 cancel 方法來執行。還提供了其他方法,以確定任務是正常完成還是被取消了。一旦計算完成,就不能再取消計算。
  • Runnable接口是爲了方便把FutureTask提交給線程池,線程池中的工作線程將調用他的 run 方法。
public interface Future<V> {

    //試圖取消對此任務的執行
    boolean cancel(boolean mayInterruptIfRunning);

    //如果在任務正常完成前將其取消,則返回 true。
    boolean isCancelled();

    //如果任務已完成,則返回 true。
    boolean isDone();

    //如有必要,等待計算完成,然後獲取其結果。
    V get() throws InterruptedException, ExecutionException;

    //如有必要,最多等待爲使計算完成所給定的時間之後,獲取其結果(如果結果可用)。
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;

}
public interface Runnable {

    public abstract void run();

}

FutureTask核心屬性

    /**
     * 狀態扭轉
     * NEW -> COMPLETING -> NORMAL //正常完成 
     * NEW -> COMPLETING -> EXCEPTIONAL //異常 
     * NEW -> CANCELLED //取消 
     * NEW -> INTERRUPTING -> INTERRUPTED //中斷
     */
    private volatile int state;//Future狀態
    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;//中斷完成

    //內部的callable,運行完成後設置爲null
    private Callable<V> callable;

    //從get方法返回或者拋出異常
    private Object outcome; //沒有volatile修飾, 通過狀態字段state讀寫保證了可見性

    //執行內部callable的線程
    private volatile Thread runner;

    /** 
     * Treiber stack 等待線程的非阻塞堆棧,存放所有等待的線程
     * 首先獲取當前最頂的節點,創建一個新節點放在堆棧上,
     * 如果最頂端的節點在獲取之後沒有變化,那麼就設置上新節點。
     * 如果 CAS 失敗,意味着另一個線程已經修改了堆棧,
     * 那麼會重新執行上述操作。
     */
    private volatile WaitNode waiters;

    static final class WaitNode {//包含了當前線程對象,並有指向下一個WaitNode的指針next,Treiber Stack就是由WaitNode組成的一個單向鏈表。
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }

FutureTask核心方法源碼分析

構造方法

    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;//volatile寫保證callable的可見性
    }

    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);//包裝成一個Callable
        this.state = NEW;//volatile寫保證callable的
    }
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }

    static final class RunnableAdapter<T> implements Callable<T> {//把Runnable包裝成一個Callable,在線程池中會執行FutureTask的run方法,在FutureTask的run方法中會執行Callable的call方法,在這個RunnableAdapter中會執行task的run方法。
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }

核心運行方法run()

    public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))//如果當前狀態不是NEW,或者狀態是NEW但是將執行線程runner用CAS從null更新爲當前線程失敗,則直接退出
            return;
        try {
            Callable<V> c = callable;//獲取當前需要執行的callable
            if (c != null && state == NEW) {//callable不爲null且狀態是NEW,則執行業務邏輯
                V result;//call方法的返回值
                boolean ran;//是否正常執行完成
                try {
                    result = c.call();//調用call方法
                    ran = true;//是正常完成設置true
                } catch (Throwable ex) {//如果拋出異常
                    result = null;//設置結果爲null
                    ran = false;//設置非正常完成false
                    setException(ex);//設置異常
                }
                if (ran)//正常完成
                    set(result);//設置返回結果
            }
        } finally {
            runner = null;//將執行線程設置爲null
            int s = state;//重新讀取狀態
            if (s >= INTERRUPTING)//如果是中斷的,處理中斷
                handlePossibleCancellationInterrupt(s);
        }
    }

    protected void set(V v) {//設置結果
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {//首先將狀態從NEW更改爲COMPLETING
            outcome = v;//將結果負值給outcome
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); //設置結果爲NORMAL,正常完成
            finishCompletion();//喚醒Treiber stack所有等待線程
        }
    }

    protected void setException(Throwable t) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {////首先將狀態從NEW更改爲COMPLETING
            outcome = t;//設置結果爲異常t
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); //設置結果爲EXCEPTIONAL,運行異常
            finishCompletion();//喚醒Treiber stack所有等待線程
        }
    }

    private void finishCompletion() {//喚醒所有等待線程
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {//如果有等待線程,設置爲q
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {//將waiters用CAS從q設置爲null,置空所有等待線程
                for (;;) {//從q開始遍歷WaitNode棧,喚醒所有的等待線程
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }

        done();//執行擴展點done方法

        callable = null; //將需要執行的callable設置爲null
    }

    private void handlePossibleCancellationInterrupt(int s) {
        if (s == INTERRUPTING)//如果狀態是INTERRUPTING,則讓出cpu等待狀態變成INTERRUPTED才結束
            while (state == INTERRUPTING)
                Thread.yield(); 
    }

V get() throws InterruptedException, ExecutionException

等待計算完成,然後獲取其結果。

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)//如果是初始化或者運行中狀態,則調用awaitDone等待執行完成後喚醒返回。
            s = awaitDone(false, 0L);//返回結果是當前Future狀態
        return report(s);//返回結果
    }

    private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {//timed標示是否超時等待,nano代表超時等待時間
        final long deadline = timed ? System.nanoTime() + nanos : 0L;//獲取最長的等待時間,支持超時是當前時間加上等待時間得到未來需要等到的最長時間點,不支持超時是0。
        WaitNode q = null;//當前線程節點
        boolean queued = false;//當前q節點是否加入等待線程棧中
        for (;;) {
            if (Thread.interrupted()) {//如果當前線程被中斷,移除當前等待節點q,然後拋出中斷異常
                removeWaiter(q);//從等待線程中移除當前節點q
                throw new InterruptedException();
            }

            int s = state;
            if (s > COMPLETING) {//如果已經完成則置空當前節點,並返回完成狀態
                if (q != null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING) //如果是COMPLETING,則意味着業務邏輯已經執行結束,讓出cpu等待最終狀態更新完成後返回
                Thread.yield();
            else if (q == null)//q==null時,初始化當前線程節點q
                q = new WaitNode();
            else if (!queued)//如果當前節點q不再等待線程棧中,則CAS將當前節點加入等待線程棧中,放在等待線程棧的頂部
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);
            else if (timed) {//如果支持超時等待,則掛起線程直到超時
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {//如果已經超時,則從等待線程棧中移除當前節點q,並返回當前狀態。
                    removeWaiter(q);
                    return state;
                }
                LockSupport.parkNanos(this, nanos);
            }
            else//如果不支持超時等待,則直接掛起線程
                LockSupport.park(this);
        }
    }

    private void removeWaiter(WaitNode node) {//移除當前等待節點node
        if (node != null) {
            node.thread = null;//下面會將node從等待隊列中移除,以thread字段爲null爲依據,出現競爭則重試
            retry:
            for (;;) {          // restart on removeWaiter race
                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                    s = q.next;
                    if (q.thread != null)
                        pred = q;
                    else if (pred != null) {
                        pred.next = s;
                        if (pred.thread == null) // check for race
                            continue retry;
                    }
                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                          q, s))
                        continue retry;
                }
                break;
            }
        }
    }

    private V report(int s) throws ExecutionException {
        Object x = outcome;
        if (s == NORMAL)//狀態是正常完成,則直接返回outcome
            return (V)x;
        if (s >= CANCELLED)//如果是取消後的狀態,則直接返回CancellationException,中斷也是屬於取消的狀態
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);//其他狀態都返回ExecutionException
    }

V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException

最多等待爲使計算完成所給定的時間之後,獲取其結果(如果結果可用)。

    public V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)//超時等待,如果從awaitDone返回時,狀態還是NEW或者COMPLETING,則意味着超時,拋出超時異常
            throw new TimeoutException();
        return report(s);
    }

boolean cancel(boolean mayInterruptIfRunning)

試圖取消對此任務的執行。如果任務已完成、或已取消,或者由於某些其他原因而無法取消,則此嘗試將失敗。當調用 cancel 時,如果調用成功,而此任務尚未啓動,則此任務將永不運行。如果任務已經啓動,則 mayInterruptIfRunning 參數確定是否應該以試圖停止任務的方式來中斷執行此任務的線程。如果此時業務方法在執行中且FutureTask狀態還是NEW時,可以取消FutureTask,但是無法停止業務方法的執行,取消之後,即使業務方法執行完畢也無法獲取執行結果,因爲FutureTask狀態是取消的。

    public boolean cancel(boolean mayInterruptIfRunning) {
        if (state != NEW)//如果是NEW狀態,則一定沒取消返回false
            return false;
        if (mayInterruptIfRunning) {//如果強制取消則中斷的方式取消任務
            if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, INTERRUPTING))//用CAS將state從NEW更新到INTERRUPTING,失敗則返回false取消失敗,成功則中斷運行任務的線程,然後將狀態設置爲INTERRUPTED,然後喚醒所有等待線程返回true取消成功
                return false;
            Thread t = runner;
            if (t != null)
                t.interrupt();//中斷運行線程(如果在線程池中執行任務,該中斷會中斷線程池中的工作線程,線程池中工作線程的run方法中會清除線程的中斷狀態)
            UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // final state
        }
        else if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED))//如果不是強制取消,用CAS將state從NEW更新到CANCELLED,失敗則返回false取消失敗,成功則喚醒所有等待線程返回true取消成功
            return false;
        finishCompletion();//喚醒所有等待線程
        return true;
    }

boolean isCancelled()

如果在任務正常完成前將其取消,則返回 true。

    public boolean isCancelled() {//大於等於CANCELLED都是取消,中斷也是取消
        return state >= CANCELLED;
    }

boolean isDone()

如果任務已完成,則返回 true。 可能由於正常終止、異常或取消而完成,在所有這些情況中,此方法都將返回 true。

    public boolean isDone() {//不是NEW就代表已經執行完成任務,等待返回了
        return state != NEW;
    }

FutureTask擴展點

任務執行完成後執行,可自定義處理邏輯,做監控或記錄等等。

    protected void done() { }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章