Callable、Future、FutureTask、Runnable

目標(biāo)

打算從以下幾個(gè)方面進(jìn)行分析:
1. Callable、Future、FutureTask、Runnable的關(guān)系;
2. 適配器模式;
3. FutureTask實(shí)例;

一、Callable、Future、FutureTask、Runnable的關(guān)系

1.1 Callable
public interface Callable<V> {
    V call() throws Exception;
}
1.2 Future
public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit);
}
1.3 RunnableFuture
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}
1.4 Runnable
public interface Runnable {
    public abstract void run();
}
1.5 FutureTask
// FutureTask擁有Runnable和Future的共性;
public class FutureTask<V> implements RunnableFuture<V>{
    public FutureTask(Callable<V> callable);
    public FutureTask(Runnable runnable, V result)
    boolean isDone();
    void run();
    V get();
    V get(long timeout, TimeUnit unit);
    V call();
}

從上面類的結(jié)構(gòu)可以看出, FutureTask擁有Runnable與Future的共性, Future與Runnable的區(qū)別是后者有返回值, 而前者沒有.

二、適配器模式

在分析FutureTask源碼之前, 其實(shí)很有必要搞懂適配器模式的概念以及特點(diǎn);

2.1 適配器概念

概念:
??適配器模式把一個(gè)類的接口變換成客戶端所期待的另一種接口, 從而使原本因接口不匹配而無法在一起工作的兩個(gè)類能夠在一起工作;
使用場(chǎng)景:
??1、系統(tǒng)需要使用現(xiàn)有的類, 而此類的接口不符合系統(tǒng)的需要, 即接口不兼容.
??2、想要建立一個(gè)可以重復(fù)使用的類, 用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類, 包括一些可能在將來引進(jìn)的類一起工作.
??3、需要一個(gè)統(tǒng)一的輸出接口, 而輸入端的類型不可預(yù)知.

2.2 對(duì)象適配器

對(duì)象適配器模式把適配的類的API轉(zhuǎn)換成目標(biāo)類的API, 與類的適配器模式不同的是, 對(duì)象的適配器模式不是使用繼承關(guān)系連接到Adaptee類, 而是使用代理關(guān)系連接到Adaptee類.


結(jié)合上圖給出一個(gè)demo

// Target角色
public interface FiveVolt {
    public int getVolt5();
}
// Adaptee角色, 需要被轉(zhuǎn)換的對(duì)象
public class Volt220 {
    public int getVolt220() {
        return 220;
    }
}
// 對(duì)象適配器模式
public class VoltAdapter implements FiveVolt {
    Volt220 mVolt220;
    public VoltAdapter(Volt220 adaptee) {
        mVolt220 = adaptee;
    }
    public int getVolt220() {
        return mVolt220.getVolt220();
    }
    @Override
    public int getVolt5() {
        return 5;
    }
}

Adaptee類(Volt220)并沒有提供getVolt5()方法, 而客戶端則期待這個(gè)方法, 為使客戶端能夠使用Adaptee類, 需要提供一個(gè)包裝類Adapter, 這個(gè)包裝類包裝了一個(gè)Adaptee的實(shí)例, 從而此包裝類能夠把Adaptee的API與Target類的API銜接起來, Adapter與Adaptee是委派關(guān)系.

一、單純就FutureTask源碼進(jìn)行分析

1.1 FutureTask兩個(gè)構(gòu)造函數(shù)

FutureTask內(nèi)部用到了適配器模式

private Callable<V> callable;
// 這里直接對(duì)FutureTask內(nèi)部的callable變量進(jìn)行賦值;
public FutureTask(Callable<V> callable) {
    this.callable = callable;
    this.state = NEW;       
}
// 1. 注意這里, 其實(shí)我們也可以借鑒, 假如FutureTask支持Callable, 后來有需求需要支持Runnable,
//    可以考慮將Runnable轉(zhuǎn)換為Callable類型, 當(dāng)我們通過FutureTask觸發(fā)Callable方法時(shí), 實(shí)際是
//    調(diào)用了Callable內(nèi)部的Runnable.run方法;
// 2. 結(jié)合1馬上再描述一下適配器模式的概念: 
//    將一個(gè)類的接口變換成客戶端所期待的另一種接口, 從而使原本因接口不匹配而無法在一起工作的兩個(gè)類能夠在一起工作;
public FutureTask(Runnable runnable, V result) {
    // 結(jié)合下面兩段代碼可知, 生成一個(gè)中間適配層RunnableAdapter, 然后通過call()最終調(diào)用Runnable.run()方法;
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       
}

public class Executors {
    public static <T> Callable<T> callable(Runnable task, T result) {
        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;
    }
    public T call() {
        task.run();
        // 這里返回傳進(jìn)來的result方法? 這個(gè)值肯定在某處被賦值了;
        return result;
    }
}
1.2 FutureTask.run
FutureTask通常都是配合線程池一起使用, 而我們知道, 線程池里面會(huì)觸發(fā)Runnable.run的執(zhí)行;
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;
            // 1.這里觸發(fā)了Callable.call()方法, 并且獲取其返回值, 結(jié)合上文可知, 假如是以
            //   第二種方式初始化的FutureTask, c實(shí)際指向中間適配層RunnableAdapter, 
            //   c.call()內(nèi)部最終調(diào)用了Runnable.run()方法;
            // 2.而返回值就是我們?cè)跇?gòu)造FutureTask時(shí)傳進(jìn)去的Result, 這里就很懵逼了, 初始化
            //   FutureTask時(shí)傳進(jìn)去Result, 任務(wù)還沒開始, Result從何而來呢?
            result = c.call();
            ran = true;
            if (ran)
                // 當(dāng)前Runnable.run()執(zhí)行完成以后, 通過set(result)對(duì)outcome進(jìn)行賦值, 從而
                // 影響到get()方法;
                set(result);
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}
1.3 FutureTask.get
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        // 這里就利用到了生產(chǎn)者-消費(fèi)者模式, 如果當(dāng)前任務(wù)沒有完成, 則調(diào)用get()方法的
        // 線程會(huì)一直阻塞在這里, 直到外部線程通過set(result)喚醒當(dāng)前線程;
        s = awaitDone(false, 0L);
    return report(s);
}

分析完FutureTask源碼之后, 還是有幾個(gè)點(diǎn)不是很明白, 比如get()返回的result其實(shí)是在初始化FutureTask時(shí)傳入的result, 這個(gè)result何時(shí)被賦值?
結(jié)合AsyncTask源碼進(jìn)行再次實(shí)戰(zhàn)分析

二、從AsyncTask源碼對(duì)FutureTask進(jìn)行實(shí)戰(zhàn)

2.1 AsyncTask兩種調(diào)用方式:

??1、創(chuàng)建AsyncTask對(duì)象, 自己實(shí)現(xiàn)doInBackground()方法, 然后調(diào)用execute()方法;
??2、直接調(diào)用AsyncTask內(nèi)部的靜態(tài)execute()方法;
因?yàn)榈谝环N方式用到了FutureTask, 所以先針對(duì)這種方式進(jìn)行分析:

2.2 AsyncTask構(gòu)造函數(shù)
public AsyncTask() {
    mWorker = new WorkerRunnable<...>() {
        public Result call() throws Exception {...}
    };

    mFuture = new FutureTask<...>(mWorker) {
        @Override
        protected void done() {...}
    };
}

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}
2.3 AsyncTask.execute(AsyncTask處理線程的第一種方式)
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
    if (mStatus != Status.PENDING) {
        switch (mStatus) {
            // mState初始值Status.PENDING, 對(duì)于同一個(gè)AsyncTask對(duì)象, 第一次執(zhí)行完execute
            // 方法以后, mState = Status.RUNNING/Status.FINISHED, 再次調(diào)用execute方法以后, 
            // 拋出異常, 這點(diǎn)可以知道AsyncTask的局限性, 不支持連續(xù)多次調(diào)用execute方法;
            case RUNNING:
                throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
            case FINISHED:
                throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
        }
    }
    mStatus = Status.RUNNING;
    onPreExecute();
    mWorker.mParams = params;
    // 在這之前的操作都是在主線程中進(jìn)行的, 下面代碼進(jìn)入到子線程中, 觸發(fā)mFuture.run()的執(zhí)行;
    exec.execute(mFuture);
    return this;
}
2.4 AsyncTask.execute(AsyncTask處理任務(wù)的第二種方式)
public static void execute(Runnable runnable) {
    sDefaultExecutor.execute(runnable);
}
2.5 AsyncTask.sDefaultExecutor
public class AsyncTask {
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
}

??execute只接受Runnable對(duì)象, mActive實(shí)際指向FutureTask, 當(dāng)Executor.execute(Runnable)時(shí)會(huì)觸發(fā)Runnable內(nèi)部run方法的執(zhí)行, 而FutureTask此時(shí)接收的是Callable對(duì)象;

FutureTask_Callable :
public class FutureTask {
    public FutureTask(Callable<V> callable) {
        this.callable = callable;
    }
    public void run() {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                setException(ex);
            }
            if (ran)
                set(result);
        }
    }
}

??1、FutureTask內(nèi)部的run()方法又是調(diào)用了Callable對(duì)象的call方法;
??2、Future提供了一系列的控制線程周期的方法;通過AsyncTask的cancel控制FutureTask的生命周期;
所以四者的關(guān)系是:
??1、由于Executor的execute()方法只接收Runnable, 并且會(huì)觸發(fā)Runnable內(nèi)部的run方法的執(zhí)行, 所以FutureTask必須實(shí)現(xiàn)Runnable;
??2、但是Runnable的run方法沒有返回值, 而有些特殊情況又需要拿到最終線程執(zhí)行的結(jié)果, 而Callable剛好可以拿到結(jié)果, 所以在其內(nèi)部持有Callable的引用;
??3、需要控制線程什么什么周期的問題, 而Future剛好提供了這些功能, 所以FutureTask又實(shí)現(xiàn)Future接口;

但是如果FutureTask需要支持Runnable怎么辦?目前run方法內(nèi)部實(shí)際調(diào)用的是Callable的call()方法:
??所以適配器模式在這里發(fā)揮了作用, 也反映了適配器的一個(gè)特點(diǎn), 是為了解決問題而生;

public class FutureTask {
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
    }
}
public class Executors{
    public static <T> Callable<T> callable(Runnable task, T result) {
        return new RunnableAdapter<T>(task, result);
    }
    private static final class RunnableAdapter<T> implements Callable<T> {
        private final Runnable task;
        private final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }
}

??FutureTask構(gòu)造函數(shù)支持傳入Runnable對(duì)象, 可以看到此時(shí)傳入的Runnable實(shí)際通過適配器模式被轉(zhuǎn)化為了Callable對(duì)象, 而Callable實(shí)際指向RunnableAdapter, RunnableAdapter內(nèi)部持有Runnable, 內(nèi)部的call方法又會(huì)出發(fā)Runnable的run方法的執(zhí)行;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容