关于android:android多线程AsyncTask二

  上篇剖析AsyncTask的一些根本用法以及不同android版本下的区别,接着本篇咱们就来全面分析一下AsyncTask的工作原理。在开始之前咱们先来理解一个多线程的知识点——Callable<V> 、Future<V>和FutureTask类

一、了解Callable<V> 、Future<V>以及FutureTask类

Callable<V>

Callable的接口定义如下:

public interface Callable<V> {   
      V   call()   throws Exception;   
}   

  Callable接口申明了一个名称为call()的办法,该办法能够有返回值V,也能够抛出异样。Callable也是一个线程接口,它与Runnable的次要区别就是Callable在线程执行实现后能够有返回值而Runnable没有返回值,Runnable接口申明如下:

public interface Runnable {
    public abstract void run();
}

  那么Callable接口如何应用呢,Callable须要和ExcutorService联合应用,其中ExecutorService也是一个线程池对象继承自Executor接口,这里就不深刻了,接着看看ExecutorService提供了那些办法供咱们应用:

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
  • submit(Callable task),传递一个实现Callable接口的工作,并且返回封装了异步计算结果的Future。
  • submit(Runnable task, T result),传递一个实现Runnable接口的工作,并且指定了在调用Future的get办法时返回的result对象。
  • submit(Runnable task),传递一个实现Runnable接口的工作,并且返回封装了异步计算结果的Future。

  因而咱们只有创立好咱们的线程对象(实现Callable接口或者Runnable接口),而后通过下面3个办法提交给线程池去执行即可。Callable接口介绍就先到这,再来看看Future时什么鬼。

Future<V>

  Future接口是用来获取异步计算结果的,说白了就是对具体的Runnable或者Callable对象工作执行的后果进行获取(get()),勾销(cancel()),判断是否实现等操作。其办法如下:

public interface Future<V> {
    //勾销工作
    boolean cancel(boolean mayInterruptIfRunning);

    //如果工作实现前被勾销,则返回true。
    boolean isCancelled();

    //如果工作执行完结,无论是失常完结或是中途勾销还是产生异样,都返回true。
    boolean isDone();

    //获取异步执行的后果,如果没有后果可用,此办法会阻塞直到异步计算实现。
    V get() throws InterruptedException, ExecutionException;

    // 获取异步执行后果,如果没有后果可用,此办法会阻塞,然而会有工夫限度,
    //如果阻塞工夫超过设定的timeout工夫,该办法将返回null。
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;

}

总得来说Future有以下3点作用:

  • 可能中断执行中的工作
  • 判断工作是否执行实现
  • 获取工作执行实现后额后果。

  然而Future只是接口,咱们根本无法将其创立为对象,于官网又给咱们提供了其实现类FutureTask,这里咱们要晓得后面两个接口的介绍都只为此类做铺垫,毕竟AsncyTask中应用到的对象是FutureTask。

FutureTask

先来看看FutureTask的实现:

public class FutureTask<V> implements RunnableFuture<V> {  

显然FutureTask类实现了RunnableFuture接口,咱们再看一下RunnableFuture接口的实现:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

  从接口实现能够看出,FutureTask除了实现了Future接口外还实现了Runnable接口,因而FutureTask既能够当做Future对象也可是Runnable对象,当然FutureTask也就能够间接提交给线程池来执行。接着咱们最关怀的是如何创立FutureTask对象,实际上能够通过如下两个构造方法来构建FutureTask

public FutureTask(Callable<V> callable) {  
}  
public FutureTask(Runnable runnable, V result) {  
}  

  从构造方法看出,咱们能够把一个实现了Callable或者Runnable的接口的对象封装成一个FutureTask对象,而后通过线程池去执行,那么具体如何应用呢?简略案例,CallableDemo.java代码如下:


package com.zejian.Executor;
import java.util.concurrent.Callable;
/**
 * Callable接口实例 计算累加值大小并返回
 */
public class CallableDemo implements Callable<Integer> {

    private int sum;
    @Override
    public Integer call() throws Exception {
        System.out.println("Callable子线程开始计算啦!");
        Thread.sleep(2000);

        for(int i=0 ;i<5000;i++){
            sum=sum+i;
        }
        System.out.println("Callable子线程计算完结!");
        return sum;
    }
}

CallableTest.java测试代码如下:

package com.zejian.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
public class CallableTest {

public static void main(String[] args) {
//第一种应用形式
//      //创立线程池
//      ExecutorService es = Executors.newSingleThreadExecutor();
//      //创立Callable对象工作
//      CallableDemo calTask=new CallableDemo();
//      //提交工作并获取执行后果
//      Future<Integer> future =es.submit(calTask);
//      //敞开线程池
//      es.shutdown();

    //第二中应用形式

    //创立线程池
    ExecutorService es = Executors.newSingleThreadExecutor();
    //创立Callable对象工作
    CallableDemo calTask=new CallableDemo();
    //创立FutureTask
    FutureTask<Integer> futureTask=new FutureTask<>(calTask);
    //执行工作
    es.submit(futureTask);
    //敞开线程池
    es.shutdown();
    try {
        Thread.sleep(2000);
    System.out.println("主线程在执行其余工作");

    if(futureTask.get()!=null){
        //输入获取到的后果
        System.out.println("futureTask.get()-->"+futureTask.get());
    }else{
        //输入获取到的后果
        System.out.println("futureTask.get()未获取到后果");
    }

    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("主线程在执行实现");
}
}

  代码非常简单,正文也很清朗,这里咱们剖析一下第2种执行形式,先前申明一个CallableDemo类,该类实现了Callable接口,接着通过call办法去计算sum总值并返回。而后在测试类CallableTest中,把CallableDemo实例类封装成FutureTask对象并交给线程池去执行,最终执行后果将封装在FutureTask中,通过FutureTask#get()能够获取执行后果。第一种形式则是间接把Callable实现类丢给线程池执行,其后果封装在Future实例中,第2种形式执行后果如下:

Callable子线程开始计算啦!
主线程在执行其余工作
Callable子线程计算完结!
futureTask.get()-->12497500
主线程在执行实现

  ok~,到此咱们对Callable、Future和FutureTask就介绍到这,有了这个常识铺垫,咱们就能够欢快的撩开AsyncTask的外部工作原理了。

二、AsyncTask的工作原理齐全解析

  在上篇中,应用了如下代码来执行AsyncTask的异步工作:

new AysnTaskDiff("AysnTaskDiff-1").execute("");

  从代码可知,入口是execute办法,那咱们就先看看execute的源码:

    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

  很显著execute办法只是一个壳子,间接调用了executeOnExecutor(sDefaultExecutor, params),其中sDefaultExecutor是一个串行的线程池,接着看看sDefaultExecutor外部实现:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/**
 * An {@link Executor} that executes tasks one at a time in serial
 * order.  This serialization is global to a particular process.
 */
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

//串行线程池类,实现Executor接口
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() { //插入一个Runnble工作
            public void run() {
                try {
                    r.run();
                } finally {
                    scheduleNext();
                }
            }
        });
        //判断是否有Runnable在执行,没有就调用scheduleNext办法
        if (mActive == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
      //从工作队列mTasks中取出工作并放到THREAD_POOL_EXECUTOR线程池中执行.
      //由此也可见工作是串行进行的。
        if ((mActive = mTasks.poll()) != null) {
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

  从源码能够看出,ArrayDeque是一个寄存工作队列的容器(mTasks),工作Runnable传递进来后交给SerialExecutor的execute办法解决,SerialExecutor会把工作Runnable插入到工作队列mTasks尾部,接着会判断是否有Runnable在执行,没有就调用scheduleNext办法去执行下一个工作,接着交给THREAD\_POOL\_EXECUTOR线程池中执行,由此可见SerialExecutor并不是真正的线程执行者,它只是是保障传递进来的工作Runnable(实例是一个FutureTask)串行执行,而真正执行工作的是THREAD\_POOL\_EXECUTOR线程池,当然该逻辑也体现AsyncTask外部的工作是默认串行进行的。顺便看一下THREAD\_POOL\_EXECUTOR线程池的申明:

//CUP核数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//外围线程数量
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//最大线程数量
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//非核心线程的存活工夫1s
private static final int KEEP_ALIVE = 1;
//线程工厂类
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
    private final AtomicInteger mCount = new AtomicInteger(1);

    public Thread newThread(Runnable r) {
        return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
    }
};
//线程队列,外围线程不够用时,工作会增加到该队列中,队列满后,会去调用非核心线程执行工作
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 * 创立线程池
 */
public static final Executor THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

  ok~,对于sDefaultExecutor,咱们先理解到这,回到之前execute办法外部调用的executeOnExecutor办法的步骤,先来看看executeOnExecutor都做了些什么事?其源码如下:

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()在此执行了!!!
   onPreExecute();
   //参数传递给了mWorker.mParams
   mWorker.mParams = params;
   //执行mFuture工作,其中exec就是传递进来的sDefaultExecutor
   //把mFuture交给线程池去执行工作
   exec.execute(mFuture);

   return this;
    }

  从executeOnExecutor办法的源码剖析得悉,执行工作前先会去判断以后AsyncTask的状态,如果处于RUNNING和FINISHED状态就不可再执行,间接抛出异样,只有处于Status.PENDING时,AsyncTask才会去执行。而后onPreExecute()被执行的,该办法能够用于线程开始前做一些筹备工作。接着会把咱们传递进来的参数赋值给 mWorker.mParams ,并执行开始执行mFuture工作,那么mWorker和mFuture到底是什么?先看看mWorker即WorkerRunnable的申明源码:

//抽象类
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}

  WorkerRunnable抽象类实现了Callable接口,因而WorkerRunnable实质上也算一个Callable对象,其外部还封装了一个mParams的数组参数,因而咱们在内部执行execute办法时传递的可变参数最终会赋值给WorkerRunnable的外部数组mParams,这些参数最初会传递给doInBackground办法解决,这时咱们发现doInBackground办法也是在WorkerRunnable的call办法中被调用的,看看其源码如下:

public AsyncTask() {
   //创立WorkerRunnable mWorker,实质上就是一个实现了Callable接口对象
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            //设置标记
            mTaskInvoked.set(true);

         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //执行doInBackground,并传递mParams参数
            Result result = doInBackground(mParams);
            Binder.flushPendingCommands();
            //执行实现调用postResult办法更新后果
            return postResult(result);
        }
    };
//把mWorker(即Callable实现类)封装成FutureTask实例
//最终执行后果也就封装在FutureTask中
    mFuture = new FutureTask<Result>(mWorker) {
        //工作执行实现后被调用
        @Override
        protected void done() {
            try {
             //如果还没更新后果告诉就执行postResultIfNotInvoked
                postResultIfNotInvoked(get());
            } catch (InterruptedException e) {
                android.util.Log.w(LOG_TAG, e);
            } catch (ExecutionException e) {
                throw new RuntimeException("An error occurred while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                //抛异样
                postResultIfNotInvoked(null);
            }
        }
    };
}

   能够看到在初始化AsyncTask时,不仅创立了mWorker(实质实现了Callable接口的实例类)而且也创立了FutureTask对象,并把mWorker对象封装在FutureTask对象中,最初FutureTask对象将在executeOnExecutor办法中通过线程池去执行。给出下图帮助了解:

  AsynTask在初始化时会创立mWorker实例对象和FutureTask实例对象,mWorker是一个实现了Callable线程接口并封装了传递参数的实例对象,而后mWorker实例会被封装成FutureTask实例中。在AsynTask创立后,咱们调用execute办法去执行异步线程,其外部又间接调用了executeOnExecutor办法,并传递了线程池exec对象和执行参数,该办法外部通过线程池exec对象去执行mFuture实例,这时mWorker外部的call办法将被执行并调用doInBackground办法,最终通过postResult去告诉更新后果。对于postResult办法,其源码如下:

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

  显然是通过Handler去执行后果更新的,在执行后果成返回后,会把result封装到一个AsyncTaskResult对象中,最初把MESSAGE\_POST\_RESULT标示和AsyncTaskResult寄存到Message中并发送给Handler去解决,这里咱们先看看AsyncTaskResult的源码:

private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

  显然AsyncTaskResult封装了执行后果的数组以及AsyncTask自身,这个没什么好说的,接着看看AsyncTaskResult被发送到handler后如何解决的。

private static class InternalHandler extends Handler {
    public InternalHandler() {
        //获取主线程的Looper传递给以后Handler,这也是为什么AsyncTask只能在主线程创立并执行的起因
        super(Looper.getMainLooper());
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) {
    //获取AsyncTaskResult
        AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
        switch (msg.what) {
            //执行实现
            case MESSAGE_POST_RESULT:
                // There is only one result
                result.mTask.finish(result.mData[0]);
                break;
                //更新进度条的标记
            case MESSAGE_POST_PROGRESS:
            //执行onProgressUpdate办法,本人实现。
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

  从Handler的源码剖析可知,该handler绑定的线程为主线线程,这也就是为什么AsyncTask必须在主线程创立并执行的起因了。接着通过handler发送过去的不同标记去决定执行那种后果,如果标示为MESSAGE\_POST\_RESULT则执行AsyncTask的finish办法并传递执行后果给该办法,finish办法源码如下:

private void finish(Result result) {
        if (isCancelled()) {//判断工作是否被勾销
            onCancelled(result);
        } else {//执行onPostExecute(result)并传递result后果
            onPostExecute(result);
        }
        //更改AsyncTask的状态为已实现
        mStatus = Status.FINISHED;
    }

  该办法先判断工作是否被勾销,如果没有被勾销则去执行onPostExecute(result)办法,内部通过onPostExecute办法去更新相干信息,如UI,音讯告诉等。最初更改AsyncTask的状态为已实现。到此AsyncTask的全副流程执行完。
  这里还有另一种标记MESSAGE\_POST\_PROGRESS,该标记是咱们在doInBackground办法中调用publishProgress办法时收回的,该办法原型如下:

protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
    //发送MESSAGE_POST_PROGRESS,告诉更新进度条
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

  ok~,AsyncTask的整体流程根本剖析完,最初来个总结吧:当咱们调用execute(Params… params)办法后,其外部间接调用executeOnExecutor办法,接着onPreExecute()被调用办法,执行异步工作的WorkerRunnable对象(本质为Callable对象)最终被封装成FutureTask实例,FutureTask实例将由线程池sExecutor执行去执行,这个过程中doInBackground(Params… params)将被调用(在WorkerRunnable对象的call办法中被调用),如果咱们覆写的doInBackground(Params… params)办法中调用了publishProgress(Progress… values)办法,则通过InternalHandler实例sHandler发送一条MESSAGE\_POST\_PROGRESS音讯,更新进度,sHandler解决音讯时onProgressUpdate(Progress… values)办法将被调用;最初如果FutureTask工作执行胜利并返回后果,则通过postResult办法发送一条MESSAGE\_POST\_RESULT的音讯去执行AsyncTask的finish办法,在finish办法外部onPostExecute(Result result)办法被调用,在onPostExecute办法中咱们能够更新UI或者开释资源等。这既是AsyncTask外部的工作流程,能够说是
Callable+FutureTask+Executor+Handler外部封装。结尾咱们献上一张执行流程,帮助大家了解整个流程:

本文转自 https://blog.csdn.net/javazejian/article/details/52464139,如有侵权,请分割删除。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理