美文网首页
Callable、Future、FutureTask、Runna

Callable、Future、FutureTask、Runna

作者: 冉桓彬 | 来源:发表于2017-05-21 22:22 被阅读56次
Callable :
public interface Callable<V> {
    V call() throws Exception;
}
Future :
public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit);
}
FutureTask :
public class FutureTask<V> implements RunnableFuture<V> ;
RunnableFuture :
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}
Runnable :
public interface Runnable {
    public abstract void run();
}

  FutureTask内部持有Callable, Thread, 将上面几个接口与类联系在一起, 所以从FutureTask源码进行分析, 如何将这些接口进行了关联;
  FutureTask内部用到了适配器模式
AsyncTask内部用到了FutureTask, 以AsyncTask为例进行分析, 争取同时搞明白AsyncTask和FutureTask;

AsyncTask有两种调用方式 :
  1、创建AsyncTask对象, 自己实现doInBackground()方法, 然后调用execute()方法;
  2、直接调用AsyncTask内部的静态execute()方法;
因为第一种方式用到了FutureTask, 所以先针对这种方式进行分析:

AsyncTask_AsyncTask() :
public abstract class AsyncTask {
    public AsyncTask() {
        mWorker = new WorkerRunnable<...>() {
            public Result call() throws Exception {...}
        };

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

  初始化AsyncTask时创建了WorkerRunnable和FutureTask对象, FutureTask持有WorkerRunnable对象的引用;

AsyncTask_WorkerRunnable :
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}
public interface Callable<V> {
    V call() throws Exception;
}

  WorkerRunnable实现于Callable接口;
  初始化AsyncTask之后便是调用execute方法让doInBackground执行于子线程中并获取返回值, 显示于主线程方法onProgressUpdate()中;

AsyncTask_execute() :
public class 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) {
                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;
        exec.execute(mFuture);
        return this;
    }
}

  1、mStatus默认为Status.PENDING, 当第一次调用execute时, mStatus随着程序的执行, 只有两个值RUNNING, FINISHED, 所以第二次调用execute时, 会抛出异常, 也即说明AsyncTask的一个缺点, 这种方式的适用场景, 单线程, 一个AsyncTask对象只能执行一个Task;
  2、虽然第二种方式可以支持执行多个Task, 但是由于execute是静态方法, 并不支持cancel等控制Task生命周期的方法;
  3、exec.execute()由线程池内部逻辑可知会触发mFuture的run方法执行;

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对象, mActive实际指向FutureTask, 当Executor.execute(Runnable)时会触发Runnable内部run方法的执行, 而FutureTask此时接收的是Callable对象;

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内部的run()方法又是调用了Callable对象的call方法;
  2、Future提供了一系列的控制线程周期的方法;通过AsyncTask的cancel控制FutureTask的生命周期;
所以四者的关系是:
  1、由于Executor的execute()方法只接收Runnable, 并且会触发Runnable内部的run方法的执行, 所以FutureTask必须实现Runnable;
  2、但是Runnable的run方法没有返回值, 而有些特殊情况又需要拿到最终线程执行的结果, 而Callable刚好可以拿到结果, 所以在其内部持有Callable的引用;
  3、需要控制线程什么什么周期的问题, 而Future刚好提供了这些功能, 所以FutureTask又实现Future接口;

但是如果FutureTask需要支持Runnable怎么办?目前run方法内部实际调用的是Callable的call()方法:
  所以适配器模式在这里发挥了作用, 也反映了适配器的一个特点, 是为了解决问题而生;

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构造函数支持传入Runnable对象, 可以看到此时传入的Runnable实际通过适配器模式被转化为了Callable对象, 而Callable实际指向RunnableAdapter, RunnableAdapter内部持有Runnable, 内部的call方法又会出发Runnable的run方法的执行;

相关文章

网友评论

      本文标题:Callable、Future、FutureTask、Runna

      本文链接:https://www.haomeiwen.com/subject/lbopxxtx.html