你是如何拿到一個(gè)線程的執(zhí)行結(jié)果的?Future體系源碼深度解析

在Java多線程開(kāi)發(fā)中愚隧,我們經(jīng)常把Thread#run()方法稱為線程的執(zhí)行單元电媳,執(zhí)行單元通常就是編寫我們的業(yè)務(wù)邏輯踏揣。我們可以通過(guò)繼承Thread然后重寫run方法實(shí)現(xiàn)自己的業(yè)務(wù)邏輯,也可以實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)自己的業(yè)務(wù)邏輯匾乓。而Runnable接口的職責(zé)主要是想把線程控制本身和業(yè)務(wù)邏輯分離開(kāi)來(lái)捞稿,但在其它的很多文章中,經(jīng)称捶欤可以看到這樣一句話娱局,創(chuàng)建線程的方式有兩種,第一種是構(gòu)造一個(gè)Thread,第二種是實(shí)現(xiàn)Runnable接口咧七,其實(shí)這種說(shuō)法衰齐,我認(rèn)為是錯(cuò)誤,至少他是特別不嚴(yán)謹(jǐn)?shù)募套琛槭裁次疫@么說(shuō)呢耻涛?我們看一下Thread類中的run()方法。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

public class Thread implements Runnable {
    private Runnable target;
    
     @Override
    public void run() {
        //如果構(gòu)造Thread的時(shí)候傳遞了Runnable瘟檩,那么將調(diào)用Runnable的run()方法抹缕,
        if (target != null) {
            target.run();
        }
       //否則就需要我們重寫Thread類run()方法了
    }
}

通過(guò)上面這兩行注釋可以清晰地看到,執(zhí)行的單元的實(shí)現(xiàn)方式是有兩種的墨辛。而不是說(shuō)創(chuàng)建線程的方式有兩種卓研,準(zhǔn)確地講,創(chuàng)建線程的方式只有一種那就是構(gòu)造Thread類背蟆,而實(shí)現(xiàn)線程的執(zhí)行單元的方式有兩種鉴分,第一種是重寫Thread的run方法,第二種是實(shí)現(xiàn)Runnable接口的run方法带膀,并且將Runnable實(shí)例用作構(gòu)造Thread的參數(shù)志珍。

現(xiàn)在我們反過(guò)來(lái)重新觀察一下,不管我們是采用重寫Thread的run垛叨,還是實(shí)現(xiàn)Runnable接口的run方法伦糯,都無(wú)法拿到線程的執(zhí)行結(jié)果柜某,為了解決這個(gè)問(wèn)題,我們常用的一種方式就是使用一個(gè)共享變量敛纲,間接地返回線程執(zhí)行的結(jié)果喂击。但在JDK1.5之后,在JUC包中提供了Future接口淤翔,而在JDK1.8中更是提供了CompletableFuture翰绊。

但本文我們主要講的是Future體系。因?yàn)镕uture體系作為線程池的重要載體旁壮,所以我們要想理解好線程池监嗜,就非常有必要先了解Future體系。

深入理解Future體系

Future體系UML

Future體系

FutureTask類實(shí)現(xiàn)了RunnableFuture接口抡谐,而RunnableFuture繼承了Runnable和Future裁奇,也就是說(shuō)FutureTask既是Runnable,也是Future麦撵。因此FuntureTask可以直接作為Thread的構(gòu)造參數(shù)直接使用了刽肠。

Callable接口

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

Callable接口類似于Runnable,都是為了成為其它線程的執(zhí)行單元而被設(shè)計(jì)出來(lái)的免胃,但與Runnable不同的是音五,Callable接口不僅擁有返回值,還會(huì)拋出異常杜秸。

Future接口

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

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

Future表示的是異步計(jì)算的結(jié)果放仗,在Future接口中润绎,提供了一些用于檢查任務(wù)執(zhí)行是否完成撬碟,等待任務(wù)執(zhí)行完成和取出任務(wù)執(zhí)行結(jié)果的方法。

  • 當(dāng)運(yùn)算完成后只能通過(guò)get()方法進(jìn)行檢索莉撇,并且調(diào)用了get()方法后出阻塞當(dāng)前線程直到任務(wù)執(zhí)行完成呢蛤。
  • 通過(guò)cancel()方法,可以取消任務(wù)棍郎。
  • 通過(guò)isCancelled()方法其障,可以判斷任務(wù)是否被取消了
  • 通過(guò)isDone()方法,可以判斷任務(wù)是否已經(jīng)完成了

RunnableFuture接口

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

RunnableFuture 繼承自Runnable和Future涂佃,即提供了可以使用Runnable來(lái)執(zhí)行任務(wù)励翼,又可以使用Future執(zhí)行獲取結(jié)果的功能,同時(shí)還擁有了取消任務(wù)辜荠,判斷任務(wù)狀態(tài)的功能汽抚。

FutureTask

public class FutureTask<V> implements RunnableFuture<V> {
    /**
     * 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;
}

一個(gè)異步可取消計(jì)算,F(xiàn)utureTask提供了Future接口的基本實(shí)現(xiàn)伯病,其中包含開(kāi)始執(zhí)行任務(wù)和結(jié)束任務(wù)的方法造烁,查詢?nèi)蝿?wù)執(zhí)行是否完成的方法,或者獲取任務(wù)結(jié)果的方法,等等惭蟋。僅當(dāng)任務(wù)執(zhí)行完成了苗桂,才能獲取到結(jié)果。
并且調(diào)用get()方法會(huì)阻塞當(dāng)前線程直到任務(wù)執(zhí)行完成告组,如果任務(wù)已經(jīng)完成了煤伟,不能重新開(kāi)始或者取消,除非這個(gè)任務(wù)調(diào)用了runAndReset()方法木缝。

FutureTask可以包裝一個(gè)Callable或者是Runnable,因?yàn)镕utureTask實(shí)現(xiàn)了Runnable對(duì)象(Callable接口類似于Runnable,Callable相對(duì)于Runnable來(lái)說(shuō)持偏,僅僅多了一個(gè)返回值和Exception拋出而已),我們可以把一個(gè)FutureTask提交給線程池的Executor來(lái)執(zhí)行氨肌。FutureTask鸿秆,除了作為一個(gè)單獨(dú)的類之外,它的protected 方法在我們自定義Task的時(shí)候是非常有用的怎囚。

看到了這里卿叽,大家有沒(méi)有思考過(guò)這樣的一個(gè)問(wèn)題呢?一個(gè)正在執(zhí)行的任務(wù)恳守,他是怎么判斷已經(jīng)取消了的考婴,又是怎么判斷執(zhí)行的任務(wù)是否已經(jīng)完成了呢,等等Future接口提供的功能催烘。如果是你沥阱,你會(huì)怎么做呢?不訪花上幾分鐘先思考一下伊群。

從上面的FutureTask的一些成員變量或者你已經(jīng)看出了端倪.但再詳細(xì)分析之前考杉,我們先看看FutureTask類怎么使用吧.

FutureTask UML

通過(guò)UML,我們可以看到舰始,有兩個(gè)構(gòu)造函數(shù)崇棠,所以說(shuō)FutureTask可以包裝一個(gè)Callable或者是Runnable。

 public static void main(String[] args) throws Exception {
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("正在下載中...");
                TimeUnit.SECONDS.sleep(3);
                return "Hello World!";
            }
        };
        FutureTask<String> futureTask = new FutureTask<>(callable);
        new Thread(futureTask).start();
        
        System.out.println("我們做的其他什么吧...");
        System.out.println("從網(wǎng)絡(luò)下載的結(jié)果為:" + futureTask.get());
        System.out.println("Finish!");


     Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("正在下載中...");
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        FutureTask<String> runnableTask = new FutureTask<>(runnable, "我是返回的結(jié)果");
        new Thread(runnableTask).start();
        System.out.println("我們做的其他什么吧...");
        System.out.println("從網(wǎng)絡(luò)下載的結(jié)果為:" + runnableTask.get());
        System.out.println("Finish!");
 }
//輸出
我們做的其他什么吧...
正在下載中...(然后等待3秒丸卷,繼續(xù)輸出)
從網(wǎng)絡(luò)下載的結(jié)果為:Hello World!
Finish!
我們做的其他什么吧...
正在下載中...(然后等待3秒枕稀,繼續(xù)輸出)
從網(wǎng)絡(luò)下載的結(jié)果為:我是返回的結(jié)果
Finish!

使用FutureTask包裝Runnable和Callable,通過(guò)Future體系,我們就可以拿到異步任務(wù)的執(zhí)行結(jié)果了,看完例子谜嫉,你應(yīng)該已經(jīng)知道FutureTask怎么使用了萎坷,但只有這個(gè)級(jí)別怎么能滿足,做人要有點(diǎn)追求沐兰,不然和八戒有什么區(qū)別哆档。

FutureTask源碼分析

public class FutureTask<V> implements RunnableFuture<V> {
    /** 任務(wù)可能出現(xiàn)的狀態(tài)轉(zhuǎn)換
     * NEW -> COMPLETING -> NORMAL
     * NEW -> COMPLETING -> EXCEPTIONAL
     * NEW -> CANCELLED
     * NEW -> INTERRUPTING -> INTERRUPTED
     */
    private volatile int state;    //任務(wù)當(dāng)前狀態(tài)
    private static final int NEW          = 0;    //新建一個(gè)任務(wù)時(shí)的狀態(tài)
    private static final int COMPLETING   = 1;    //任務(wù)即將執(zhí)行完成的狀態(tài)
    private static final int NORMAL       = 2;    //任務(wù)正常執(zhí)行結(jié)束的狀態(tài)
    private static final int EXCEPTIONAL  = 3;    //任務(wù)異常時(shí)的狀態(tài)
    private static final int CANCELLED    = 4;    //任務(wù)被取消的狀態(tài)
    private static final int INTERRUPTING = 5;    //任務(wù)即將被中斷的狀態(tài)
    private static final int INTERRUPTED  = 6;    //任務(wù)已經(jīng)被中斷的狀態(tài)
}

其中可以把一個(gè)FutureTask的這7種狀態(tài)分為三種:

  • 第一種:初始化狀態(tài):NEW
  • 第二種:中間狀態(tài):COMPLETING,INTERRUPTING
  • 第三種:終端狀態(tài):NORMAL僧鲁,EXCEPTIONAL虐呻,CANCELLED象泵,INTERRUPTED

初始化一個(gè)FutureTask的時(shí)候,state為初始化值NEW斟叼,當(dāng)僅且當(dāng):調(diào)用了set()偶惠,setException()和cancel()方法,才會(huì)將狀態(tài)轉(zhuǎn)換成終端狀態(tài)朗涩。并且中間狀態(tài)繼續(xù)的時(shí)間是比較短暫的忽孽。

//這是一個(gè)內(nèi)部的callable對(duì)象,我們通過(guò)構(gòu)造函數(shù)傳入的callable對(duì)象將會(huì)保存在這里
//當(dāng)任務(wù)執(zhí)行完成后谢床,callable會(huì)被置為null
private Callable<V> callable;
//保存任務(wù)執(zhí)行的結(jié)果或者是get()方法拋出的異常兄一,通過(guò)state來(lái)實(shí)現(xiàn)同步的
private Object outcome; 
//執(zhí)行callable任務(wù)的線程,它是CAS操作识腿。
private volatile Thread runner;
//等待線程的Treiber棧出革,Treiber是一種算法,Treiber棧是一種無(wú)阻塞棧渡讼。
private volatile WaitNode waiters;

public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
}

public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
}

創(chuàng)建FutureTask的時(shí)候骂束,會(huì)把runnable或者callable保存到 callable成員變量里邊,同時(shí)會(huì)把state置為NEW

 // Unsafe mechanics
    private static final sun.misc.Unsafe UNSAFE;
    private static final long stateOffset;      //任務(wù)狀態(tài)的偏移量
    private static final long runnerOffset;   //runner線程的偏移量   
    private static final long waitersOffset;  //Treiber棧的偏移量   
  //有了這些偏移量后成箫,UNSAFE就能得到他們對(duì)應(yīng)的值了
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = FutureTask.class;
            stateOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("state"));
            runnerOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("runner"));
            waitersOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("waiters"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }

//任務(wù)起動(dòng)就調(diào)這個(gè)方法展箱。
public void run() {
        //compareAndSwapObject方法有四個(gè)參建:第一個(gè)是某個(gè)對(duì)象,第二個(gè)是相對(duì)偏移量蹬昌,有了這個(gè)偏移量 
        //就可以知道混驰,內(nèi)存塊對(duì)應(yīng)變量X的值了,第三個(gè)是:預(yù)期值皂贩,第四個(gè)是:更新值,如果X == 預(yù)期值栖榨,那 
        //么就將X的值更新為更新值,并返回true先紫,或者返回fasle.「是一個(gè)CAS操作」
        
        //如果state == NEW,則runner = Thread.currentThread() ,返回true治泥,取反之后,進(jìn)入后面的計(jì)算遮精。

        //如果state不是NEW的情況,說(shuō)明任務(wù)已經(jīng)被執(zhí)行了败潦,直接返回  
       //避免任務(wù)重新執(zhí)行
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                //這一塊的代碼本冲,建議大家反復(fù)讀多幾次
                //這一個(gè)ran變量用得真的是精彩,他主要的為了:他主要是不捕捉set()方法的異常
                //如果這里我們直接在  result = c.call();后面直接調(diào)set();那么最終的done()方法很可能出現(xiàn)異常
                //就會(huì)導(dǎo)致 setException()調(diào)用了劫扒,從而生命周期變成了
                //NEW -> COMPLETING -> NORMAL-> EXCEPTIONAL
                boolean ran;
                try {
                    result = c.call();//如果任務(wù)執(zhí)行的時(shí)間比較少檬洞,那么在這里就體現(xiàn)出來(lái)了
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
         
            runner = null;
            //在任務(wù)執(zhí)行的過(guò)程中,可能會(huì)調(diào)用cancel()
            //這里主要是不想讓中斷操作逃逸到run()方法之外
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
}

//更改當(dāng)前任務(wù)的狀態(tài)并把任務(wù)執(zhí)行的結(jié)果寫入到outcome當(dāng)中沟饥,最后由get()取出來(lái)用
protected void set(V v) {
        //將當(dāng)前任務(wù)狀態(tài)置為:COMPLETING
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            //將當(dāng)前任務(wù)狀態(tài)置為:NORMAL
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
}

//完成任務(wù)后的收尾操作
private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
             //  將Treiber棧的棧頂置為null添怔,
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                //遍歷Treiber棧并喚醒所有節(jié)點(diǎn)的線程
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;//把當(dāng)前節(jié)點(diǎn)置為無(wú)效節(jié)點(diǎn)
                        LockSupport.unpark(t);//這里喚醒的是awaitDone()阻塞的線程
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
        //一個(gè)鉤子方法湾戳,本類中,它是一個(gè)空實(shí)現(xiàn)广料,在子類中可以重寫它砾脑。
        done();
        //最后把callable置為null.
        callable = null;        // to reduce footprint
    }
//修改當(dāng)前任務(wù)的狀態(tài)
protected void setException(Throwable t) {
        //將當(dāng)前任務(wù)狀態(tài)置為:COMPLETING
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = t;
            //將當(dāng)前任務(wù)狀態(tài)置為:EXCEPTIONAL
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
            finishCompletion();
        }
}

//取消任務(wù)。如果是false  NEW->CANCELLED     true: NEW ->INTERRUPTING->INTERRUPTED
public boolean cancel(boolean mayInterruptIfRunning) {
         //如果當(dāng)前任務(wù)是新建任務(wù)艾杏,則將其置為INTERRUPTING或者CANCELLED
        if (!(state == NEW &&
              UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    //使用了線程中斷的方法來(lái)達(dá)到取消任務(wù)的目的
                    Thread t = runner;
                    if (t != null)
                        t.interrupt();
                } finally { // final state
                    //如果當(dāng)前任務(wù)不是新建任務(wù)韧衣,則將其狀態(tài)置為INTERRUPTING
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
}

通過(guò)前面的這些分析,相應(yīng)FutureTask的整個(gè)生命周期應(yīng)該特別清淅了

FutureTask生命周期
    //任務(wù)是滯被取消了购桑。包括cancel(false);和cancel(true);
    public boolean isCancelled() {
        return state >= CANCELLED;
    }
    
    //任務(wù)是否結(jié)束畅铭,不一定是成功任務(wù),取消了勃蜘,出異常了硕噩,被中斷了,也是結(jié)束
    public boolean isDone() {
        return state != NEW;
    }

這兩個(gè)方法比較簡(jiǎn)單缭贡,我們就多說(shuō)什么榴徐,接下來(lái)看FutureTask的核心, get()的過(guò)程

//獲取任務(wù)執(zhí)行的結(jié)果
 public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)//如果任務(wù)還沒(méi)執(zhí)行完成匀归,就等待任務(wù)先執(zhí)行完成
            s = awaitDone(false, 0L);
        return report(s);
}
//獲取任務(wù)執(zhí)行的結(jié)果坑资,并且有超時(shí)機(jī)制
public V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        //帶有超時(shí)時(shí)間的get(),如果超過(guò)指定時(shí)間穆端,就會(huì)拋出一個(gè)TimeoutException
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException();
        return report(s);
}
 //等待任務(wù)完成
 private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        //超時(shí)時(shí)間袱贮,如果使用了超時(shí)的get()才起作用,否則這個(gè)值不起作用
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            if (Thread.interrupted()) {//如果線程被中斷了
                removeWaiter(q);//移除無(wú)效節(jié)點(diǎn)
                throw new InterruptedException();//就拋出一個(gè)中斷異常
            }

            int s = state;//把任務(wù)的當(dāng)前狀態(tài)保存到s變量里
            if (s > COMPLETING) {//如果當(dāng)前狀態(tài)大于COMPLETING体啰,說(shuō)明任務(wù)已經(jīng)結(jié)果了
                if (q != null)//如果q不為空攒巍,就說(shuō)明已經(jīng)被初始化了
                    q.thread = null;//回收q.thread
                return s;//返回任務(wù)的狀態(tài)
            }
           // 如果當(dāng)前的任務(wù)狀態(tài)為COMPLETING,因?yàn)樗耐A舻臅r(shí)間非常短荒勇,通過(guò)yield()嘗試把時(shí)間片
          //交給其他線程處理柒莉,然后重試
            else if (s == COMPLETING)
                Thread.yield();
          //初始化q節(jié)點(diǎn),然后重試
            else if (q == null)
                q = new WaitNode();
            //將q節(jié)點(diǎn)壓入棧沽翔,它是一個(gè)cas操作
            else if (!queued)
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                     q.next = waiters, q);
            //如果有超時(shí)限制的話兢孝,判斷是否超時(shí),如果沒(méi)有超時(shí)就重試仅偎,如果超時(shí)了跨蟹,就把q節(jié)點(diǎn)從棧中遇除
            else if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {//超時(shí)了
                    removeWaiter(q);//移除無(wú)效節(jié)點(diǎn)
                    return state;
                }
                LockSupport.parkNanos(this, nanos);//LockSupport是一個(gè)并發(fā)工具,這里表示等待nanos秒后喚醒
            }
            else
                LockSupport.park(this);//開(kāi)始阻塞線程橘沥,直到任務(wù)完成了才會(huì)再次喚醒了在finishCompletion()中喚醒
        }
}
/**
 *  將某個(gè)節(jié)點(diǎn)置為無(wú)效節(jié)點(diǎn)窗轩,并清除棧中所有的無(wú)效節(jié)點(diǎn)
 * (通過(guò)前面的分析,應(yīng)該可以推斷出座咆,無(wú)效的節(jié)點(diǎn)痢艺,其實(shí)就是指節(jié)點(diǎn)內(nèi)部的thread == null) 
 *  那么產(chǎn)生無(wú)效節(jié)點(diǎn)的情況就有三種了
 *  (1):線程被中斷了
 *  (2):s > COMPLETING仓洼,當(dāng)前的任務(wù)狀態(tài)> COMPLETING
 *  (3):超時(shí)
 */
private void removeWaiter(WaitNode node) {
        if (node != null) {
            node.thread = null;//為了GC回收node節(jié)點(diǎn)中的thread成員變量
            retry:
            for (;;) {          // restart on removeWaiter race
                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                    s = q.next;//將q節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn),保存到s
                    if (q.thread != null)//如果當(dāng)前節(jié)點(diǎn)q為有效節(jié)點(diǎn)堤舒,則前pred節(jié)點(diǎn)置為當(dāng)前節(jié)點(diǎn)色建,繼續(xù)遍歷
                        pred = q;
                    //如果當(dāng)前節(jié)點(diǎn)q為無(wú)效節(jié)點(diǎn),并且有前驅(qū)節(jié)點(diǎn)
                    else if (pred != null) {
                        //刪除當(dāng)前節(jié)點(diǎn)
                        pred.next = s;
                        //如果前驅(qū)節(jié)點(diǎn)也是一個(gè)無(wú)效節(jié)點(diǎn)植酥,則重新遍歷镀岛,否則就代表清理完成了
                        if (pred.thread == null) // check for race
                            continue retry;
                    }
                    //如果當(dāng)前節(jié)點(diǎn)q是無(wú)效節(jié)點(diǎn)并且沒(méi)有前驅(qū)節(jié)點(diǎn)(也就是棧頂節(jié)點(diǎn)),則將棧頂置為當(dāng)前節(jié)點(diǎn)q的    后繼節(jié)點(diǎn)友驮,再遍歷
                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                          q, s))
                        continue retry;
                }
                break;
            }
        }
}

//取出執(zhí)行結(jié)果
 private V report(int s) throws ExecutionException {
        Object x = outcome;//我們?cè)趕et()方法的時(shí)候把結(jié)果寫進(jìn)outcome的
        if (s == NORMAL)//如果是正常直接返回任務(wù)執(zhí)行的結(jié)果
            return (V)x;
        if (s >= CANCELLED)//如果是被取消了漂羊,或者是被中斷了就返回一個(gè)CancellationException
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);//或者返回一個(gè)ExecutionException
}

至此,整個(gè)FutureTask的源碼已經(jīng)分析完了卸留,最后總結(jié)一下關(guān)于Future體系的一些重要點(diǎn)走越,第一,關(guān)于保存任務(wù)執(zhí)行的結(jié)果耻瑟,F(xiàn)uture體系主要是利用了Callable接口的call函數(shù)旨指,如果你想在任務(wù)執(zhí)行結(jié)束后返回一些你預(yù)期的值,就可以使用public FutureTask(Runnable runnable, V result){}喳整,這里的result就是你的預(yù)期值谆构。第二個(gè)就是FutureTask的生命周期了,通過(guò)前面的分析框都,相信生命周期的流程認(rèn)真閱讀的你已經(jīng)理解記憶了搬素。第三點(diǎn)就是,獲取任務(wù)執(zhí)行的結(jié)果了魏保,這一塊其實(shí)是貫穿全文熬尺,可能需要你多讀幾遍源碼,但其實(shí)思路也是比較簡(jiǎn)單的谓罗,①如果在獲取值是粱哼,任務(wù)已經(jīng)完成了,則直接就返回結(jié)果②如果在獲取任務(wù)執(zhí)行的結(jié)果時(shí)檩咱,任務(wù)還沒(méi)有完成揭措,則開(kāi)始阻塞,直到任務(wù)任務(wù)完成税手。其中還涉汲到一個(gè)棧對(duì)線程的管理蜂筹,如果在阻塞其間,任務(wù)被中斷了芦倒,或者超時(shí)了,又或者任務(wù)已經(jīng)完成了不翩,都需要進(jìn)行資源的回收兵扬。

文章到這里麻裳,相信如何拿到一個(gè)線程的執(zhí)行結(jié)果?這個(gè)題目器钟,你自己已經(jīng)有答案了津坑,但其實(shí)這個(gè)只是開(kāi)始,有這個(gè)知道傲霸,相信在閱讀線程池的源碼時(shí)疆瑰,你將更加的如魚得水。當(dāng)然昙啄,緊接著穆役,我也會(huì)推送JDK線程池的源碼解析。好了梳凛,謝謝您的閱讀耿币,下期再見(jiàn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末韧拒,一起剝皮案震驚了整個(gè)濱河市淹接,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌叛溢,老刑警劉巖塑悼,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異楷掉,居然都是意外死亡厢蒜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門靖诗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)郭怪,“玉大人,你說(shuō)我怎么就攤上這事刊橘”刹牛” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵促绵,是天一觀的道長(zhǎng)攒庵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)败晴,這世上最難降的妖魔是什么浓冒? 我笑而不...
    開(kāi)封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮尖坤,結(jié)果婚禮上稳懒,老公的妹妹穿的比我還像新娘。我一直安慰自己慢味,他們只是感情好场梆,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布墅冷。 她就那樣靜靜地躺著,像睡著了一般或油。 火紅的嫁衣襯著肌膚如雪寞忿。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天顶岸,我揣著相機(jī)與錄音腔彰,去河邊找鬼。 笑死辖佣,一個(gè)胖子當(dāng)著我的面吹牛霹抛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凌简,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼上炎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了雏搂?” 一聲冷哼從身側(cè)響起藕施,我...
    開(kāi)封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凸郑,沒(méi)想到半個(gè)月后裳食,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芙沥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年诲祸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片而昨。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡救氯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出歌憨,到底是詐尸還是另有隱情着憨,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布务嫡,位于F島的核電站甲抖,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏心铃。R本人自食惡果不足惜准谚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望去扣。 院中可真熱鬧柱衔,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)羽氮。三九已至或链,卻和暖如春赐写,著一層夾襖步出監(jiān)牢的瞬間刑桑,已是汗流浹背仰猖。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工途事, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留慎颗,地道東北人铸史。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓举庶,卻偏偏與公主長(zhǎng)得像怒坯,于是被迫代替她去往敵國(guó)和親粒没。 傳聞我的和親對(duì)象是個(gè)殘疾皇子筛婉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

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

  • 你以為的生活是怎樣?是你行走兩三步爽撒,腳下生花?是你來(lái)來(lái)回回穿插的掌聲响蓉? 是你沿途是鮮花,困難里有瑪麗蘇枫甲? 不,生活...
    王卡洛夫閱讀 550評(píng)論 0 1
  • 君不見(jiàn)黃河之水天上來(lái)想幻。奔流到海不復(fù)回。 君不見(jiàn)高堂明鏡悲白發(fā)脏毯。朝如青絲暮成雪闹究。 人生得意須盡歡抄沮。莫使金樽空對(duì)月跋核。 ...
    SuperK軍閱讀 328評(píng)論 0 0
  • 頸椎病的檢查方法的選擇指南之二: 大叔說(shuō):我主要是手痛砂代,肩痛,手無(wú)力麻木率挣,這是頸椎病嗎刻伊?應(yīng)該是肩周炎吧?我...
    2e7b0cc28f8b閱讀 1,150評(píng)論 0 0