FutureTask分析

首先我們看下FutureTask與其他接口的關(guān)系圖


image.png

可以看到FutureTask實(shí)現(xiàn)了RunnableFuture,RunnableFuture繼承了Runnable和Future接口。

在我們的demo例子中 FutureTask如何得知線程執(zhí)行完畢的楷扬。

    //FutureTask類
    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;
    //當(dāng)我們new出來FutureTask時(shí)候随橘,這個(gè)state為0
    public FutureTask(Runnable runnable, V result) {
        //調(diào)用了Executors中的方法
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       
    }
  // Executors類
  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> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        } 
        //在重寫call方法中會(huì)調(diào)用task的run方法。
        public T call() {
            task.run();
            return result;
        }
    }

我們執(zhí)行線程start之后,因?yàn)镕utureTask實(shí)現(xiàn)了RunnableFuture维贺,RunnableFuture繼承了Runnable和Future接口澈圈,所以我們會(huì)運(yùn)行到FutureTask的run方法彬檀。

    // FutureTask類
    public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    /*call會(huì)調(diào)用call中Runnable的run方法,所以 call會(huì)調(diào)用我們demo中 
                      重寫的run方法 */
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
               //如果正確執(zhí)行完run的內(nèi)容,則去置state的狀態(tài)
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
   //修改state裝填并且喚醒掛起的線程
   protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); 
            finishCompletion();
        }
    }
   //當(dāng)任務(wù)執(zhí)行完畢會(huì)喚醒所有掛起的線程瞬女,這里的waiters是一個(gè)鏈表窍帝,后面會(huì)有說明
    private void finishCompletion() {
        for (WaitNode q; (q = waiters) != null;) {
           // CAS直接將掛起線程鏈表waiters指向?yàn)榭?            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                 //喚醒所有掛起的線程
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; 
                    q = next;
                }
                break;
            }
        }
        done();
        callable = null;      
    }

在demo中,當(dāng)我們執(zhí)行FutureTask類的get方法時(shí)

  public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }
 // 獲取state的狀態(tài)
   private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            if (Thread.interrupted()) {
                removeWaiter(q);
                throw new InterruptedException();
            }
            int s = state;
            //如果處于已經(jīng)完成或者異常狀態(tài)拆魏,直接返回
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
            //如果處于COMPLETING盯桦,則讓線程再次參與競(jìng)爭(zhēng)cpu
            else if (s == COMPLETING) 
                Thread.yield();
            else if (q == null)
                q = new WaitNode();
            else if (!queued)
                //形成一個(gè)后進(jìn)先出的鏈表
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                     q.next = waiters, q);
            else if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    removeWaiter(q);
                    return state;
                }
                  //線程掛起
                LockSupport.parkNanos(this, nanos);
            }
            else
              //線程掛起
                LockSupport.park(this);
        }
    }

在上面的源碼中慈俯,我們可以看出來,awaitDone方法中我們會(huì)對(duì)比當(dāng)前state拥峦,如果state==new贴膘,我們會(huì)將線程掛起,等待finishCompletion方法中喚醒掛起的線程略号。

private V report(int s) throws ExecutionException {
        Object x = outcome;
        //如果線程正確執(zhí)行完畢刑峡,則返回結(jié)果,否則拋出異常
        if (s == NORMAL)
            return (V)x;
        if (s >= CANCELLED)
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末玄柠,一起剝皮案震驚了整個(gè)濱河市突梦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌羽利,老刑警劉巖宫患,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異这弧,居然都是意外死亡娃闲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門匾浪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來皇帮,“玉大人,你說我怎么就攤上這事蛋辈∈羰埃” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵冷溶,是天一觀的道長(zhǎng)渐白。 經(jīng)常有香客問我,道長(zhǎng)挂洛,這世上最難降的妖魔是什么礼预? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮虏劲,結(jié)果婚禮上托酸,老公的妹妹穿的比我還像新娘。我一直安慰自己柒巫,他們只是感情好励堡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堡掏,像睡著了一般应结。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天鹅龄,我揣著相機(jī)與錄音揩慕,去河邊找鬼。 笑死扮休,一個(gè)胖子當(dāng)著我的面吹牛迎卤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玷坠,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蜗搔,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了八堡?” 一聲冷哼從身側(cè)響起樟凄,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎兄渺,沒想到半個(gè)月后缝龄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溶耘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年二拐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凳兵。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖企软,靈堂內(nèi)的尸體忽然破棺而出庐扫,到底是詐尸還是另有隱情,我是刑警寧澤仗哨,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布形庭,位于F島的核電站,受9級(jí)特大地震影響厌漂,放射性物質(zhì)發(fā)生泄漏萨醒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一苇倡、第九天 我趴在偏房一處隱蔽的房頂上張望富纸。 院中可真熱鬧,春花似錦旨椒、人聲如沸晓褪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涣仿。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間好港,已是汗流浹背愉镰。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钧汹,地道東北人岛杀。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓脯丝,卻偏偏與公主長(zhǎng)得像口锭,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闸盔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容