AsyncTask 源码解读
Contents
前面有一篇文章说了说线程池,如果对线程池还不太了解的,请务必先了解一下,因为这次要说的 AsyncTask 正是基于 线程池,它的源码只有 600 多行,刨去一堆注方法释,在刨去定义的线程池,代码真的不多!
网上已经有很多对 AsyncTask 解读了,多数把源码一段一段讲解,由表及里,循序渐进,容易理解,在文章末尾我也会贴出解读的非常棒的文章链接。想一睹为快的可以直接拉到底部点进去,哈哈,我这里就随意分析了。先从 FutureTask 说起。
FutureTask
先来看一张 FutureTask 的 UML 关系图
简单解释一下:
- Callable
这个类与 Runnable 类似,里面的 call() 方法也是设计在 子线程 调用的,优势是可以返回结果或者抛出异常。
- call() 方法什么时候会执行呢?既然在子线程跑,肯定得有线程,所以,Callable
一般是传递到 ExecutorService 当中去的,通过 submit(Callable task) ,最终调用 execute() 方法去执行。 - call() 方法执行的结果是怎样的?记得 AsyncTask 有个必须实现的 doInBackground() 方法吗? call() 方法体里面 就调用了 doInBackground() 方法来让我们自己实现耗时逻辑。
- FutureTask 主要用来 调度任务。内部需要传入一个 Callable
对象。
- 它很好的弥补了 Thread 的不足? 可以再看下上面的图,RunnableFuture 继承了 Runnable 接口和 Future 接口,而 FutureTask 实现了 RunnableFuture 接口。所以它既可以作为 Runnable 被线程执行,又可以作为 Future 获得操作线程已经获取执行结果。
- ExecutorService + Callable
+ FutureTask 获取执行结果的 小栗子 3.0 之后,AsyncTask 默认的 线程池是 SerialExecutor ,是一个 以串行顺序执行任务 的池子,通过 同步锁 使之串行化执行。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76class WorkerRunnable implements Callable<Integer>{
public Integer call() throws Exception {
System.out.println("子线程在进行耗时的计算任务");
Thread.sleep(3000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}
}
public class Test {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
WorkerRunnable mWorker = new WorkerRunnable();
FutureTask<Integer> mFuture = new FutureTask<Integer>(mWorker);
executor.submit(mFuture);
System.out.println("主线程在执行任务");
try {
System.out.println("mWorker运行结果"+ mFuture.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("所有任务执行完毕");
}
}
```
运行结果:
```html
子线程在进行耗时的计算任务
主线程在执行任务
mWorker运行结果4950
所有任务执行完毕
```
4. 到这里,可以猜想一下,AsyncTask 是 获怎么运行的?
- AsyncTask 构造时,初始化了 Callable<V> mWorker 以及 FutureTask<V> mFuture,并将 mWorker 作为参数传递给了 mFuture,这样这个 mWorker 就可以控制了,线程池 execute 的时候,会调用 mFuture.run()方法,该方法会 回调 mWorker.call() 方法,最终调用调用者的 doInBackground() 方法,大致流程就是这样。后面通过 Handler 将 执行结果回调给 调用者。
下面粗略分析一下 AsyncTask 这个类。
## AsyncTask
1. 内部线程池的定义及配置
```java
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;
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);
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
我们可以根据需求选择默认线程池1
2
3
4//串行实例化
new FileAsyncTask().extcute();
//并行实例化
new FileAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,""); - 构造方法
上面分析过了,直接贴代码WorkerRunnable是一个实现了Callable的抽象类,扩展了Callable多了一个Params参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}1
2
3private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
} - execute() 方法
当执行 execute() 时,实际上是调用了 executeOnExecutor 方法。这里传递了两个参数,一个是sDefaultExecutor,一个是 params。sDefaultExecutor 其实是一个 SerialExecutor 对象,实现了串行线程队列。params 最终会赋给doInBackground方法去处理。AsyncTask 的异步任务有三种状态1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
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();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}exec.execute(mFuture) 方法 最终会进入 SerialExecutor 的 execute() 方法里,前面说过它是一个串行化的执行过程,看下 SerialExecutor 的代码:1
2
3PENDING 待执行状态。当 AsyncTask 被创建时,就进入了 PENDING 状态。
RUNNING 运行状态。当调用 executeOnExecutor,就进入了 RUNNING 状态。
FINISHED 结束状态。当 AsyncTask 完成(用户 cancel() 或任务执行完毕)时,就进入了 FINISHED 状态。r.run() 方法实际上调用的是 futureTask 的 run() 方法,再跟进去:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
}
}
}这里,取出了这个 callable 对象,并调用了它的 call() 方法,于是又回调到了 AsyncTask 初始化 mWorker 的回调方法中,这里调用了 doInBackground() 的抽象方法,并 postResult() 到主线程中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
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 {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}在InternalHandler的handleMessage中开始处理消息,InternalHandler的源码如下所示:1
2
3
4
5
6
7
8private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17private static class InternalHandler extends Handler {
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;
}
}
} - cancel() 方法
AsyncTask.cancel(mayInterruptIfRunning); 实际上调用的是 mFuture 的 cancel() 方法, 源码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
流程图
整个 AsyncTask 都是以代码在理流程,这里放几张 网上找的非常好的流程图,看完印象更加深刻
非常棒的文章
Title: AsyncTask 源码解读
Author: mjd507
Date: 2016-12-06
Last Update: 2024-01-27
Blog Link: https://mjd507.github.io/2016/12/06/AsyncTask-Source-Code/
Copyright Declaration: This station is mainly used to sort out incomprehensible knowledge. I have not fully mastered most of the content. Please refer carefully.