Android中的多线程操作是比比皆是,之前有对线程间通信方式的Handler进行源码梳理,今天就对AsyncTask的工作原理进行源码分析:
准备
AsyncTask背后的实现原理也是基于Handler和Thread的,只不过Android给我们做了很好的封装,我们可以直接拿来使用.
首先,我们都知道AsyncTask有三个主要的泛型参数:
- Params : 在执行AsyncTask时下需要传入的参数,主要在后台任务中心执行需要
- Process : 在后台任务指定的过程中,需要向外显示任务执行的程度,就需要使用这个参数
- Result :主要用在任务执行完毕后,需要有结果的返回时
然后我们看看AsyncTask的常见的几个方法:
- onPreExecute() : 主线程执行,在后台任务执行之前调用,主要进行界面的初始化
- doInBackground() :主要的后台耗时任务就在这里执行
- onProcessUpdate() : 主要在显示后台任务完成程度的时候调用
- onPostExecute() : 任务执行完毕后进行结果的返回时调用
接着任务是怎么开始执行的呢?AsyncTask也为我们提供了方法,
- execute() : 在new AsyncTask().execute(); 执行后.我们的AsyncTask就正式执行了.
时序图
源码分析
当调用AsyncTask的execute()方法时,就是开始执行AsyncTask,我们就从execute()方法开始看起
/frameworks/base/core/java/android/os/AsyncTask.java
1 AsyncTask.execute()
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
我们可以看到,这里要求AsyncTask的execute()方法要求在MainThread(主线程)中执行.然后在execute()中调用然后在execute()中调用executeOnExecutor()方法;我们要看看这个executeOnExecutor()方法做了什么?
1.1 AsyncTask.executeOnExecutor
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
...
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
@MainThread
protected void onPreExecute() {
}
1.2 AsyncTask.onPreExecute
在executeOnExecutor中,首先调用了onPreExecute()方法,这个方法一般都是用于后天任务的初始化话操作的,它一般使用我们在自己的代码中重写相关的操作,所以在AsyncTask中是空实现;接下来有个赋值操作,将传进来的参数params赋值给mWorker的mParams变量,我们看看这个mWorker和mParams又是什么?
1.3 WorkerRunnable
private final WorkerRunnable<Params, Result> mWorker;
...
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
这个mWorker 是WorkerRunnable对象,WorkerRunnable实现了Callable接口。这个Callable接口有一个call()方法;WorkerRunnable有个Params数组。我们这里需要关心mWorker的初始化,它在是在AsyncTask的构造函数中舒适化的,
1.4 AsysncTask 构造函数
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
...
result = doInBackground(mParams);
...
postResult(result);
...
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
...
postResultIfNotInvoked(get());
...
}
};
}
AsysncTask的构造函数主要做了以下几件事:
- 获取一个handler对象 : 发送和处理doInBackGround()方法执行的结果
- 执行doInBackGround()方法:主要就是后台任务的处理
- postResult():在doInBackground()方法后通过handler发送将执行结果发出去
- 将mWorker入参创建FutureTask :将Worker对象放到FutureTask,FutureTask实现了Future,
1.4.1 getMainHandler
这里的handler对象一般情况下是通过getMainhandler()方法获取的;
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
getMainhandler()方法里面,如果sHandler不为空,就会new 了一个新的InternalHandler对象。这个InternalHandler类继承Handler,在InternalHandler的handleMessage主要处理两件事
- 处理任务完成返回的结果:调用finish()方法处理任务收尾工作
- 更新处理任务完成的程度:调用onPreExecute()方法向外部更新任务处理程度
1.4.2 doInBackGround
@WorkerThread
protected abstract Result doInBackground(Params... params);
在doInBackground中就是用来处理后台任务,运行在工作线程中, 主要业务逻辑代码有开发人员在继承类中来实现,所以在AsysncTask中也是空实现;
1.4.3 postResult
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
在这postResult()方法中,主要就是给InternalHandler发送后台任务处理的结果,然后在InternalHandler的handleMessage中相应的进行处理
1.4.4 mFuture = new FutureTask<Result>(mWorker)
接下里,我们就需要把之前的在WorkerRunnable对象放到FutureTask中,以实现异步执行的功能。
以上,我们就了解到AsyncTask是怎么把任务提交到FutureTask中去。但是这些任务FutureTask并没有执行。我们需要开启线程池中的线程执行他们。那么接下里,我们就继续看看,那些任务是怎么被成功执行的,
1.5 sDefaultExecutor.execute
紧接着调用了exec.execute()方法,传入的参数是mFuture;而这个mFuture就是我们的FutureTask实例;这个exec就是在步骤1中传进来的sDefaultExecutor,接下来我们就去看看sDefaultExecutor是个什么东西呢?
2 SerialExecutor
2.1 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();
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() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
2.2 SerialExecutor.execute()
从上面的三段源码段中我们可以知道这个sDefaultExecutor是个SerialExecutor对象,而SerialExecutor是一个实现Executor借口的串行执行任务的类;它的execute()有是在干什什么呢?
在SerialExecutor的execute()方法被synchronize修饰,然后在execute()方法中调动mTasks.offer();这个mTasks的定义就在SerialExecutor类里面.
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
mTasks就是一个装有Runnable的双向链表.调用它的offer()方法,将新的runnable任务插入到mTask链表的后面.然后调用SerialExecutor的scheduleNext()方法;
2.3 SerialExecutor.scheduleNext()
SerialExecutor的scheduleNext()方法也被synchronized修饰.在scheduleNext方法中将mTask中的runnable任务poll出来,调用 THREAD_POOL_EXECUTOR.execute(mActive)来执行任务;接着我们就要看看你这个THREAD_POOL_EXECUTOR又是个什么东东?
3 THREAD_POOL_EXECUTOR
这个THREAD_POOL_EXECUTOR看名字就可以知道是和线程池有关,我们继续看看;
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
果然,THREAD_POOL_EXECUTOR是个Executor对象,但是我们都知道EXecutor是个接口,那么它的赋值我们就要了解了;我么接上面的源码段继续看.在static修饰的代码块中,创建了一个ThreadPoolExecutor对象threadPoolExecutor,然后将threadPoolExecutor赋值给了THREAD_POOL_EXECUTOR;然后在
3.1 ThreadPoolExecutor.execute()
在获取到ThreadPoolExecutor的对象后,就这调用它的Execute()方法,我们接着看看这个execute()方法的实现:
ThreadPoolExecutor执行被安排的是任务有时候是在未来某个时间执行的,这个任务也许是在一个新的线程或者是一个已经存在线程池中的线程.如果需要被执行的任务不能正常被提交,或者因为当前线程的Executor已经挂了,或者是是当前线程池的线程数量已经满了,这个任务会被拒绝.
public void execute(Runnable command) {
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
在ThreadPoolExecutor的execute()方法中,主要是分别对三种情况进行处理
-
如果当前的工作线程数量小于corethread 数量,那么就会常创建新的coreThread.来处理被提交的任务
-
如果Executor正常运行,并且程功把任务排好序,然后重新检查线程池的状态,判断是线程池是拒绝还是接受任务
-
如果我们成功吧任务排好序,我们需要尝试开启新的线程,如果失败,那么我们有可能已经被关闭或者已经饱和,那我们就需要拒绝此任务.
3.2 addWorker
下面我们就主要针对添加任务来看看addWorker()是怎么添加处理任务的;
private boolean addWorker(Runnable firstTask, boolean core) {
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
...
w = new Worker(firstTask);
final Thread t = w.thread;
...
t.start();
workerStarted = true;
...
return workerStarted;
}
这个addWorker()方法主要任务如上所示,主要就是将任务封装Worker对象,我们就来了解一下这个Worker类是什么
4. Worker
这个Worker是个什么东西呢?这个Worker主要维护运行任务的线程的中断控制状态,以及其他次要的一些数据记录.
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
...
}
我们关注一下这个Worker的构造,知道这个Worker使用hashSet来管理.他的两个主要成员变量firstTask和thread,firstTask就是提交的任务,thread就是相应的处理任务的线程.这个线程是通过ThreadFactory来创建的;
在成功获取到Worker对象后,然后将然后调用Worker中thread的start()方法开始处理任务线程进行处理.这个的thread 调用start后,就会执行任务【mWorker】中的run方法,这里就回到了WorkerRunnable的run方法中:就会去执行AsysncTask中的doInBackground,onPostExecute等方法。
以上,我们就将AsyncTask的一般运行流程梳理完了。