美文网首页
源码探索系列15---那个AsyncTask里面的FutureT

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

作者: SanjayF | 来源:发表于2015-12-29 22:19 被阅读78次

    很久前在写源码探索系类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());
    

    打印的结果是:

    before1451383552900
    result=call-result
    after1451383555900
    

    时间刚好差了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有关系吗?

    后记

    这次没有后记的内容。

    相关文章

      网友评论

          本文标题:源码探索系列15---那个AsyncTask里面的FutureT

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