源码探索系列15---那个AsyncTask里面的FutureTask

来源:互联网 发布:爱钱进可靠吗 知乎 编辑:程序博客网 时间:2024/06/06 01:31

很久前在写源码探索系类2–AsyncTask时候有提及到这个类,现在在这里把FutureTaskFutureCallback,这三个火枪手的关系温习下

起航

就让我们进入主题,开始说说这个FutureTask吧。

在安装开发过程中,系统限制我们对于耗时的任务是不能执行在主线程的,必须单独开一个线程去做。
所以我们在开发过程的一种写法是下面这样

1. 用Runnable

    new Thread(new Runnable() {            @Override            public void run() {             //do something             ...             myHandler.sendMessage(msg);               }    }).run();

但有时候我们需要这个线程的运算结果,可我们没办法直接获取,因此安卓配套了一个Handler给我们用,利用他发送消息会我们的主线程,执行一些更新任务等。

2.用Callable

除了使用Runnable,我们还可以使用Callable,示例如下

ExecutorService executor = Executors.newCachedThreadPool();Future future= executor.submit(new MyCallableTask());System.out.println(" result=" + future3.get());class MyCallableTask implements Callable<String> {    @Override    public String call() throws Exception {                                  return "call-result";    }}

我们的Callable和Runnable的一点区别是可以有返回值了,而且能抛出异常。
不过他只能用ExecutorService来执行,不能用在新线程中new Thread(Runnable r)
但获得他的返回值,好像不是很方便。而且这个get操作是堵塞线程的,例如改成下面这样

System.out.println("before" + System.currentTimeMillis());System.out.println(" result=" + future3.get());System.out.println("after" + System.currentTimeMillis());

打印的结果是:

before1451383552900result=call-resultafter1451383555900

时间刚好差了3秒钟。

很显然,有时候我们需要异步的,希望等运行结束了通知下我,我去获取结果,然后做点什么,改怎办呢?如果不用AsyncTask,Thread+Handler的方式?看下这个FutureTask能不能帮我们点什么

FutureTask

我们先看下示例代码:

ExecutorService executor = Executors.newCachedThreadPool();MyFutureTask futureTask = new MyFutureTask(new MyCallableTask());executor.submit(futureTask);class MyCallableTask implements Callable<String> {     @Override     public String call() throws Exception {         Thread.sleep(3000);         return "call-result";     } }class MyFutureTask extends FutureTask<String> {    public MyFutureTask(Callable<String> callable) {        super(callable);    }    @Override    protected void done() {        try {            System.out.println("执行完毕,结果是:"+get());        } catch (Exception e) {            e.printStackTrace();        }    }}

我们的done()函数会被调用,当这个任务结束返回结果的话。
小小问题来了,为何这个FutureTask可以被Executor执行?我们看下他的构造

 public class FutureTask<V> implements RunnableFuture<V> public interface RunnableFuture<V> extends Runnable, Future<V>

他实现了RunnableFuture,是个混血儿!混血儿!混血儿!Amazing
就像是AsyncTask封装好了,帮我们解脱这些繁琐的事情一样,有用!

既然这样,我们去看下他的内部的run方法吧

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

他会去调用我们的callable.call()函数,然后把结果扔给Set()函数,如果一切正常的话。
我们看下set里面的

protected void set(V v) {    if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {        outcome = v;        U.putOrderedInt(this, STATE, NORMAL); // final state        finishCompletion();    }}

最后调用的是finishComPletion()

private void finishCompletion() {    // assert state > COMPLETING;        ....    done();    callable = null;        // to reduce footprint}

我们看到他调用了done函数了,而且最后把callbale清清清清清清清了,因为我们拿到结果了。
这个done() 函数里面什么也没有,主要是通知我们计算完毕,我们可以在这个时候去调用get()函数去获取结果了。


说到这,想提下,知道为何AsyncTask不能够执行两次吗?和这个FutureTask有关系吗?

后记

这次没有后记的内容。

0 0
原创粉丝点击