AsyncTask 源码分析 - 简介

459 阅读4分钟

这是我参与更文挑战的第10天,活动详情查看: 更文挑战

本文基于 Android 9.0.0 的源代码

framework/base/core/java/andorid/os/AsyncTask.java

简介

之前讲解了能够在后台工作线程中执行耗时任务的IntentService框架,在这里我们继续学习Android提供的另外一个异步执行任务的框架AsyncTask,它和IntentService既有相似点也有不同点,其相似之处在于都能在新的线程中执行耗时任务防止阻塞主线程,不同之处在于AsyncTask能够追踪任务的执行过程和结果并在主线程中显示出来。

知识储备

LinkedBlockingQueue 链阻塞队列

阻塞队列BlockingQueue被广泛使用在“生产者-消费者”问题中,其原因是BlockingQueue提供了可阻塞的插入和移除的方法。当队列容器已满,生产者线程会被阻塞,直到队列未满;当队列容器为空时,消费者线程会被阻塞,直至队列非空时为止。 LinkedBlockingQueue 类实现了 BlockingQueue 接口。LinkedBlockingQueue 内部以一个链式结构(链接节点)对其元素进行存储。如果需要的话,这一链式结构可以选择一个上限。如果没有定义上限,将使用 Integer.MAX_VALUE 作为上限。LinkedBlockingQueue 内部以 FIFO(先进先出)的顺序对元素进行存储。队列中的头元素在所有元素之中是放入时间最久的那个,而尾元素则是最短的那个。

ArrayDeque

数组队列 ArrayDeque的特点

  • 大小自增长的队列
  • 内部使用数组存储数据
  • 线程不安全
  • 内部数组长度为8、16、32….. 2的n次方
  • 头指针head从内部数组的末尾开始,尾指针tail从0开始,在头部插入数据时,head减一,在尾部插入数据时,tail加一。当head==tail时说明数组的容量满足不了当前的情况,此时需要扩大容量为原来的二倍。

ExecutorService 执行器服务

java.util.concurrent.ExecutorService 接口表示一个异步执行机制,使我们能够在后台执行任务。因此一个 ExecutorService 很类似于一个线程池。

ExecutorService 简单实现

ExecutorService executorService = Executors.newFixedThreadPool(10);  

executorService.execute(new Runnable() {  
    public void run() {  
        System.out.println("Asynchronous task");  
    }  
});  

executorService.shutdown();

首先使用 newFixedThreadPool() 工厂方法创建一个 ExecutorService。这里创建了一个十个线程执行任务的线程池。 然后,将一个 Runnable 接口的匿名实现类传递给 execute() 方法。这将导致 ExecutorService 中的某个线程执行该 Runnable。

ThreadPoolExecutor 线程池执行者

ava.util.concurrent.ThreadPoolExecutor 是 ExecutorService 接口的一个实现。ThreadPoolExecutor 使用其内部池中的线程执行给定任务(Callable 或者 Runnable)。

构造方法:

//构造方法
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

下面看看几个参数的含义及作用

  • corePoolSize — 核心线程数,即允许闲置的线程数目
  • maximumPoolSize — 最大线程数,即这个线程池的容量
  • keepAliveTime — 非核心线程的闲置存活时间
  • unit — 上一个参数的单位
  • workQueue — 任务队列(阻塞队列)
  • threadFacotry — 线程创建工厂
  • handler — 当线程池或者任务队列容量已满时用于 reject

Callable&&Future

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

简单来讲,Callable接口等价于Runable,call()等价于run(),区别在于它是有返回值的。 我们可以通过ExecutorService调用Callable,执行后将返回Future对象,比如: Future<String> future = Executors.newSingleThreadExecutor().submit(mCallable);

 
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接口两个方法着重理解下,一是cancel(boolean mayInterruptIfRunning),顾名思义就是终止线程,二是get(),它会阻塞线程,直到Callable的call()返回对象,并以此作为返回值。至于mayInterruptIfRunning这个boolean值的含义,大家看看FutureTask中相应的源码就直到了,其实只是多了thread.interrupt()的逻辑而已。结合Callable的代码,Future的使用如下:

Future<String> future = Executors.newSingleThreadExecutor().submit(mCallable);
//阻塞线程,等待Callable.call()的返回值
String result = future.get();

FutureTask

public class FutureTask<V> implements RunnableFuture<V>

public interface RunnableFuture<V> extends Runnable, Future<V> {  
    /** 
     * Sets this Future to the result of its computation 
     * unless it has been cancelled. 
    */  
    void run();  
}```

FutureTask的继承关系来看,它既是Runable也是Future,所以我们可以把当做Runable来使用,同时它也具备Future的能力,可以终止线程,可以阻塞线程,等待Callable的执行,并获取返回值。另外要注意的是,它的构造函数是public FutureTask(Callable callable),因此实例化FutureTask时需要Callable对象作为参数。