线程任务的调度
内部会创建一个进程作用域的线程池来管理要运行的任务,也就就是说当你调用了AsyncTask#execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Therad。对于内部的线程池不同版本的,Android的实现方式是不一样的:
Android2.3以前的版本,也即SDK/API 10和以前的版本。
内部的线程池限制是5个,也就是说最大只能同时开启5个线程工作(并行),超过了5个的话,其他的线程只能等待,直到有线程执行结束了,才能继续执行,内部默认使用的是THREAD_POOL_EXECUTOR线程池,这个也是AsyncTask的缺陷,对于android2.3以前这个是无法解决的。
android3.0之后,也就是SDK/API11和之后的版本。
Google也意识到了这个问题,因此做了一些调整,即#execute()后,任务是一个一个执行了,使用了SERIAL_EXECUTOR线程池执行任务:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
sDefaultExecutor的源码如下:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
扩展类AsyncTaskCompat
由于在3.0之后,google修改了Excutor的默认线程池为SERIAL_EXECUTOR,所以如果在3.0之后,要想使用平行5个的线程池,可以使用该类,当前前提最好是那种线程不超过5个,而又需要与UI进行交互的场景,也就是说该类可以让你回到2.3之前的效果。
其源代码如下:
public class AsyncTaskCompat {
/**
* Executes the task with the specified parameters, allowing multiple tasks to run in parallel
* on a pool of threads managed by {@link android.os.AsyncTask}.
*
* @param task The {@link android.os.AsyncTask} to execute.
* @param params The parameters of the task.
* @return the instance of AsyncTask.
*/
public static <Params, Progress, Result> AsyncTask<Params, Progress, Result> executeParallel(
AsyncTask<Params, Progress, Result> task,
Params... params) {
if (task == null) {
throw new IllegalArgumentException("task can not be null");
}
//进行版本的判断,如果是3.0之前,则直接使用task.execute(params);
//AsyncTaskCompatHoneycomb.executeParallel(task, params)实际上是显示调用了线程池THREAD_POOL_EXECUTOR
if (Build.VERSION.SDK_INT >= 11) {
// From API 11 onwards, we need to manually select the THREAD_POOL_EXECUTOR
AsyncTaskCompatHoneycomb.executeParallel(task, params);
} else {
// Before API 11, all tasks were run in parallel
task.execute(params);
}
return task;
}
}
//AsyncTaskCompatHoneycomb源码代码
class AsyncTaskCompatHoneycomb {
static <Params, Progress, Result> void executeParallel(
AsyncTask<Params, Progress, Result> task,
Params... params) {
//这里显示调用了THREAD_POOL_EXECUTOR,所以就可以使用该线程池了
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
}
其他
当然,对于想要自己规定线程池的个数,可以显示调用该方法:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {...}
我们只需要传入Executor即可,如使用自定义的CorePoolSize为开启7个线程的线程池:Executor(Executors.newFixedThreadPool(7))。