线程之AsyncTask的完全解析
来源:互联网 发布:算法求最小公倍数 编辑:程序博客网 时间:2024/06/08 13:58
1. 概述
AsyncTask是一种轻量的异步任务类,它中间封装了线程池和Handler,所以我们使用它可以更方便地执行后台线程操作和UI更新的切换。
2. 用法
AsyncTask是一个抽象的泛型类,它提供了Params、Progress、Result这三个泛型参数,其中Params是异步任务类参数的类型,Progress表示任务执行的进度类型,Result表示后台任务返回的结果类型。它有4个方法。
- onPreExecute(),在执行任务之前的操作,运行在ui线程上。
- doInBackground(),要执行的任务,运行在线程上。
- onProgressUpdate(),进度更新,运行在ui线程上,需要在doInBackground手动调用publishProgress方法。
- onPostExecute(),执行任务之后调用,运行在ui线程上。
3. 源码解析
3.1 线程池之ThreadPoolExecutor
在源码中可以看到这样一组变量定义:
private static final// 手机CPU数量int CPU_COUNT = Runtime.getRuntime().availableProcessors();// 线程池中核心线程数量的大小int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));// 线程池中最大线程数量int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;int KEEP_ALIVE_SECONDS = 30;ThreadFactory sThreadFactory = new ThreadFactory() {};
这上面所有的参数它们有一个共同的作用,就是利用这些参数实例化一个线程池
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
通过public static final的定义我们得知AsyncTask内部维护了一个静态线程池,默认情况下,AsyncTask的任务就是交给这个线程池来执行的。
从上面分析我们能知道AsyncTask内部维护了一个THREAD_POOL_EXECUTOR的线程池。
3.2 Executor接口的实现SerialExecutor
SerialExecutor是一个实现Executor的AsyncTask的静态内部类
private static class SerialExecutor implements Executor { // 一个双端队列,用来存放任务Rnnable类 ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); // 当前正在执行的Runnable Runnable mActive; // 我们调用SerialExecutor的execute()会将Runnable再次封装,将其放入到双端队列mTasks的最后面。判断mActive是否为null来判断当前是否有任务在执行,如果没有任务在执行那么从任务队列中去一个任务去执行,如果有任务在执行则等待这个任务执行完毕后在finally中去取下一个任务 public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } // mTasks取出一个Runnable将其交给mActive,然后再交由THREAD_POOL_EXECUTOR线程池来执行 protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } }}
从上面的代码分析中我们可以知道,当mTasks中的runnable作为参数传递给THREAD_POOL_EXECUTOR执行execute方法时,会在线程池的工作线程中执行匿名内部类Runnable中的try-finally代码段,即在工作线程中执行.run()方法,可以看到不管是正常执行还是抛出异常最终都会调用scheduleNext()方法,用来继续将mTasks中的下一个runnable传递出去,所以我们能到处结论,SerialExecutor是一个一个执行任务的是串行执行而非并行执行的。
另外,SerialExecutor将mTasks中的Runnable交给了THREAD_POOL_EXECUTOR去执行,说明SerialExecutor中的任务实际上是由THREAD_POOL_EXECUTOR线程池来处理的。
3.3 AsyncTask定义的字段
AsyncTask中定义的字段有这些
// 一个静态内部类,它绑定了UI线程private static InternalHandler sHandler;// 通过handler发布result的message codeprivate static final int MESSAGE_POST_RESULT = 0x1;// 通过handler发布progress的message codeprivate static final int MESSAGE_POST_PROGRESS = 0x2;// AsyncTask默认使用SERIAL_EXECUTOR作为它的Executor,所以默认情况下AsyncTask是串行而非并行执行的private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;// 是一个实现了Callable接口的对象private final WorkerRunnable<Params, Result> mWorker;// Future利用mWorker实例化private final FutureTask<Result> mFuture;// AsyncTask默认是未开始状态private volatile Status mStatus = Status.PENDING;// 任务是否被取消的标识private final AtomicBoolean mCancelled = new AtomicBoolean();// 任务是否真正开始了的标识private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
3.3.1 表示状态的枚举类型
AsyncTask内部定义了一个枚举类型用来表示任务执行的状态。
// 分别表示还没有执行任务、正在执行任务、任务结束public enum Status { PENDING, RUNNING, FINISHED,}
AsyncTask的状态一定是这样变化的:PENDING->RUNNING->FINISHED。
3.3.2 默认线程池
sDefaultExecutor的初始值为SERIAL_EXECUTOR,利用我们对SERIAL_EXECUTOR的理解我们知道AsyncTask默认是串行执行的。
3.3.3 InternalHandler
我们之前在提到AsyncTask的概念时说过,AsyncTask封装了线程池和Handler,这个sHandler就是AsyncTask的静态内部类InternalHandler
private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @SuppressWarnings({"unchecked","RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { 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: result.mTask.onProgressUpdate(result.mData); break; } }}
我们通过InternalHandler构造函数可以知道,sHandler和ui线程上的Looper相关联所以说明sHandler绑定了ui线程。
3.3.4 mWorker和mFuture
mWorker是一个WorkerRunnable的类,WorkerRunnable是实现Callable接口的抽闲类,Callable和Runnable相似,Runnable内部定义了run方法,Callable内部定义了call方法,call方法可以有返回值,但run方法不能有返回值。
mFuture是FutureTask的对象,由于Executor的execute方法需要接收Runnable对象,但是再执行完任务之后我们又需要返回result,这是变利用了FutureTask对象,它同时实现了Callable和Runnable接口,它的构造函数需要传入一个Callable对象,所以我们也可以将FutureTask对象mFuture传递给Executor的execute方法去执行。
当任务执行完之后会调用FutureTask的done方法,在任务执行的过程中还可以随时调用FutureTask的cancel方法取消执行任务,取消任务之后仍然会调用done方法。
3.4 AsyncTask的构造函数
AsyncTask的构造函数实际上就是对mWorker和mFuture的实例化。
mWorker的实例化
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { // 将任务开始标识设为true mTaskInvoked.set(true); Result result = null; // 将call方法设置为后台线程级别 try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // 在线程池中执行doInBackground()方法,并返回result result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { // 将结果交由postResult()方法 postResult(result); } return result; }};
mFuture的实例化
mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground); } catch (CancellationException e) { postResultIfNotInvoked(null); } }};
mWorker其实是一个Callable类型的对象。实例化mWorker,实现了Callable接口的call方法。call方法是在线程池的某个线程中执行的,而不是运行在主线程中。在线程池的工作线程中执行doInBackground方法,执行实际的任务,并返回结果。当doInBackground执行完毕后,将执行完的结果传递给postResult方法。postResult方法我们后面会再讲解。
mFuture是一个FutureTask类型的对象,用mWorker作为参数实例化了mFuture。在这里,其实现了FutureTask的done方法,我们之前提到,当FutureTask的任务执行完成或任务取消的时候会执行FutureTask的done方法。done方法里面的逻辑我们稍后再将。
3.5 AsyncTask.execute()
我们来看一下execute是如何运作的
3.5.1 executeOnExecutor()
在实例化AsyncTask之后需要调用AsyncTask的execute方法来执行任务
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
可以看到实际上execute调用了executeOnExecutor方法。
@MainThreadpublic final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: throw new IllegalStateException(""); case FINISHED: throw new IllegalStateException(""); } } // 在开始执行任务之前将状态改变 mStatus = Status.RUNNING; // 真正执行任务之前调用该方法 onPreExecute(); // mWorker.mParams = params; exec.execute(mFuture); return this;}
mStatus状态如果不是PENDING就抛出异常,说明AsyncTask只可以执行一次任务。
因为@MainThread我们知道executeOnExecutor()方法是运行在ui线程上的,所以onPreExecute()也是运行在ui线程上的。
再之后,调用了exec.execute(mFuture),开始执行任务,由于exec默认是SERIAL_EXECUTOR,所以会将包含任务的mFuture放入到静态队列中去,根据SERIAL_EXECUTOR的队则去排队执行任务。
开始执行任务之后,会调用mWorker中的call方法,从而执行doInBackground()方法之后,会将执行结果传递给postResult()方法。
3.5.2 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;}
它会通过sHandler来发送带有Result的信息给ui线程,这其中出现了AsyncTaskResult,它是什么?
3.5.3 AsyncTaskResult
private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; }}
mTask表明了它是哪个AsyncTask的结果,mData表示存储的数据
3.5.4 sHandler的handleMessage()
public void handleMessage(Message msg) { 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: result.mTask.onProgressUpdate(result.mData); break; }}
执行result.mTask.finish()方法,就是执行当前AsyncTask的finish方法
3.5.5 finish()
private void finish(Result result) { if (isCancelled()) { //如果任务被取消了,那么执行onCancelled方法 onCancelled(result); } else { //将结果发传递给onPostExecute方法 onPostExecute(result); } //最后将AsyncTask的状态设置为完成状态 mStatus = Status.FINISHED; }
finish方法一目了然,如果任务被取消了则执行onCancelled()方法,如果没有则执行onPostExecute()方法,因为sHandler是和ui线程关联的,所以这两个方法都运行在ui线程中。
3.5.6 done()
在mWorker的call()执行完毕之后,会调用mFuture的done()方法,我们查看源码知道不管任务是正常执行完毕还是被取消都会调用postResultIfNotInvoked()方法。
private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (!wasTaskInvoked) { //只有mWorker的call没有被调用才会执行postResult方法 postResult(result); }}
我们在mWorker的call方法中将mTaskInvoked设为true,所以如果mWorker的call方法没有被执行则会调用postResult()方法。
如果AsyncTask正常执行完成的时候,call方法都执行完了,mTaskInvoked设置为true,并且在call方法中最后执行了postResult方法,然后进入mFuture的done方法,然后进入postResultIfNotInvoked方法,由于mTaskInvoked已经执行,所以不会执行再执行postResult方法。
如果在调用了AsyncTask的execute方法后立马就执行了AsyncTask的cancel方法(实际执行mFuture的cancel方法),那么会执行done方法,且捕获到CancellationException异常,从而执行语句postResultIfNotInvoked(null),由于此时还没有来得及执行mWorker的call方法,所以mTaskInvoked还未false,这样就可以把null传递给postResult方法。
由此AsyncTask的细节应该都清楚了。
4. 加深理解
4.1 例子
我们知道串行执行任务调用execute(),并发执行时调用executeOnExecutor()方法。
调用execute时,默认会将sDefaultExecutor设置为SERIAL_EXECUTOR,SERIAL_EXECUTOR是一个串行执行的过程。
调用executeOnExecutor(sDefaultExecutor, xx),我们将sDefaultExecutor变量设置为我们传递进去的线程池,或者直接使用AsyncTask内部维护的线程池ThreadPoolExecutor,这样任务的传递给ThreadPoolExecutor的execute()方法,它的方法则是一个并行执行的过程。
为了验证这个结论,我们写下了这几个测试的伪代码
class MyAsyncTask01 extends AsyncTask<String, Object, String>{ @Override protected void onPreExecute() { Log.i(Tag, "01-onPreExecute"); super.onPreExecute(); } @Override protected String doInBackground(String... params) { for ( String string : params ){ Log.i(Tag, "01-doInBackground:" + string); Thread.sleep(5000); } return "完成"; } @Override protected void onPostExecute(String s) { super.onPostExecute(s); Log.i(Tag, "01-onPostExecute:" + s); }}class MyAsyncTask02 extends AsyncTask<String, Object, String>{ @Override protected void onPreExecute() { Log.i(Tag, "02-onPreExecute"); super.onPreExecute(); } @Override protected String doInBackground(String... params) { for ( String string : params ){ Log.i(Tag, "02-doInBackground:" + string); } return "完成"; } @Override protected void onPostExecute(String s) { super.onPostExecute(s); Log.i(Tag, "02-onPostExecute:" + s); }}MyAsyncTask01 myTask01 = new MyAsyncTask01();MyAsyncTask02 myTask02 = new MyAsyncTask02();
运行:
// 第1组myTask01.execute("a"); myTask02.execute("b");// 第2组myTask01.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "a");myTask02.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "b");
第1组
因为它是串行执行的,所以等待任务1执行完毕后才会执行任务2。
第2组
它是并行执行的,所以任务1和任务2是同时执行的。
4.2 doInbackground()竟然没有执行
我们知道并行执行要调用executeOnExecutor()方法,但是我的doInbackgroud方法竟然没有执行或者是等了很久才执行,其实原因这样的。AsyncTask内部维护了一个静态线程池ThreadPoolExecutor,因为它是静态的,所以它内部管理的不仅仅是我们定义AsyncTask任务的线程,它还有可能管理其他任务的线程,假如app后台运行了很多下载任务,任务都是利用AsyncTask并发下载的,ThreadPoolExecutor线程池中没有空闲线程了,这时候我们开启一个异步任务AsyncTask,由于没有空闲线程,所以你的doInbackground()方法需要等待有线程空闲下来才开始执行,才造成了以上的情况。我们可以模拟一下这个情况。
for (int i=0; i<100; i++){ MyAsyncTask01 t1 = new MyAsyncTask01(); t1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "a");}MyAsyncTask02 t2 = new MyAsyncTask02();t2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "b");
由图可见,足足过了25秒,t2任务才开始执行。这时候我们应该讲线程池换成我们自定义的线程池。
- 线程之AsyncTask的完全解析
- AsyncTask源码终极完全解析----结合Android线程池谈谈AsyncTask任务个数和线程的最大数量问题
- Android多线程—AsyncTask的完全解析
- Android AsyncTask完全解析
- 一步步完全解析AsyncTask
- Android AsyncTask完全解析
- Android AsyncTask完全解析
- Android AsyncTask完全解析
- Android AsyncTask完全解析
- Android AsyncTask完全解析
- 【AsyncTask使用】Android AsyncTask 使用完全解析
- Android AsyncTask完全解析,站在源码的角度上
- Android 从源码的角度带你完全解析AsyncTask
- Android 从源码的角度带你完全解析AsyncTask
- 线程之间的数据传输之AsyncTask
- android 线程之AsyncTask
- 异步线程之AsyncTask
- 线程通信之AsyncTask
- 杂记通信http
- 所用的日常 Git 命令!
- LED恒流驱动IC汇总
- 【更新】Microsoft Visio类库Aspose.Diagram 9月新版V17.9发布 | 附下载
- oracle字段中将空格替换
- 线程之AsyncTask的完全解析
- php Array 常用函数
- 1095 [ZJOI2007]Hide 捉迷藏
- 堆排序-Heap Sort
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
- Protect the Docker daemon socket(TLS)
- PHP设计模式之-----高级工厂模式
- java 判断一棵二叉树是否为平衡二叉树
- 翻转二叉树