熟悉AsyncTask的人都知道,AsyncTask中维护了两个线程池
//第一个线程池,用作执行具体任务
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;
}
/**
* 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 final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
//注意sDefaultExecutor ,马上就会提到
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
其中第二个线程池SERIAL_EXECUTOR 只用作排队,具体任务的执行仍由THREAD_POOL_EXECUTOR进行处理;
让我们从AsyncTask的execute函数查看执行原理;
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
可以看到,execute函数默认调用了executeOnExecutor 方法,默认执行线程是sDefaultExecutor,即默认使用SERIAL_EXECUTOR来执行任务;
那么这个SERIAL_EXECUTOR到底做了什么呢
@MainThread
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;
}
可以看到这个executeOnExecutor函数,首先确保该AsyncTask只执行一次,然后执行onPreExecute,真正的执行逻辑是调用了SERIAL_THREADPOOL的execute方法;
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();
}
}
//任务队列中如果有新任务,则将该任务从队列中取出,交给THREAD_POOL线程池执行;
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
再找到这个类的execute方法。可以非常清楚的知道,这个线程池仅仅用作排队使用,并且保证了THREAD_POOL一次只执行一个任务;
单看这一步,其实可以认为 两个线程池是没有必要的,一个执行,一个排队,就是标准的newSingleThreadExecutor ,那么为什么设计时候要使用两个线程池提高资源浪费呢;
答案就在马上揭晓:
我们正常使用asyncTask,往往是AysnTask.execute();内部帮我们调用了executeOnExecutor(sDefaultExecutor, params);
但是Google同样给我们留下了并行的方法,我们可以自己调用executeOnExecutor(THREAD_POOL);来并行执行任务;而且这种策略有一个好处;默认的队列执行是线性的,但是通过源码看出,线性的意思是,只有SERIAL_EXECUTOR提交的任务需要线性执行,我们通过THREAD_POOL执行的任务是不受影响的,即使正在运行,只要mActive为空,那么SERIAL_EXECUTOR将会提交新任务给THREAD_POOL执行;因此,这种设计,能够让线性的保持线性,不需要线性的任务就直接插队进行并行处理;
下面展示THREAD_POOL的构造源码,一次最多只能并发执行4个任务;
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
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;
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;
}
回到开始,我们能看到,AsyncTask的任务提交函数都通过注解设定了MainThread,这是为什么呢?
首先,我们回到使用AsyncTask的使用上,首先,他先在主线程执行onPreExecute(),可以做一些加载图标,对话框,进度条之类的。再在子线程执行doInBackground(),最后,我们希望在执行结束后,在主线程执行onPostExecute(),取消对话框 进度条,或者其他的View的更新。
因此,我们需要在切换子线程和主线程;
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
private Handler getHandler() {
return mHandler;
}
.........
.........
.........
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;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
我们在主线程创建,保证了handler在主线程创建,便于onProgressUpdate, onPostExecute等 可以正常更新UI。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
下面给出一个简单的Demo,展示一下并发AsyncTask和串行AsyncTask的使用结果;
//创建10个串行AysnTask ,延迟500ms输出
for(int i =0;i<10;i++) {
new AsyncTask<Void, Void, Void>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(Void aVoid) {
}
@Override
protected Void doInBackground(Void... voids) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
Log.e("AsynTask" +
"", "finished");
return null;
}
}.execute(null, null, null);
}
//每隔200ms 创建1个并行AysnTask ,延迟500ms输出
for(int i =0;i<10;i++) {
new AsyncTask<Void, Void, Void>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(Void aVoid) {
}
@Override
protected Void doInBackground(Void... voids) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
Log.e("AsynTask" +
"", "finishedCon");
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
忽略指令执行耗时,我们一次性创建了10个串行和1个并行,之后每0.2s创建了1个并行,创建完10个后 花费1.8秒;此时打印了3个串行;
我们看一下打印结果
//创建了第10个串行和一个并行,等待500ms打印第一个串行和第一个并行,然后第二个串行进入等待
08-16 20:38:40.202 26282-26346/com.example.administrator.singletoptest E/AsynTask: finished
08-16 20:38:40.202 26282-26347/com.example.administrator.singletoptest E/AsynTask: finishedCon
//再过200ms,此时第700ms,打印第二个并行
08-16 20:38:40.405 26282-26348/com.example.administrator.singletoptest E/AsynTask: finishedCon
//900ms,第三个并行
08-16 20:38:40.607 26282-26349/com.example.administrator.singletoptest E/AsynTask: finishedCon
//1000ms, 第二个并行等待500ms后,打印
08-16 20:38:40.707 26282-26350/com.example.administrator.singletoptest E/AsynTask: finished
//1100,第三个并行,打印;
08-16 20:38:40.810 26282-26351/com.example.administrator.singletoptest E/AsynTask: finishedCon
//1300
08-16 20:38:41.013 26282-26352/com.example.administrator.singletoptest E/AsynTask: finishedCon
//1500,第三个串行打印完成,第5个并行打印完成,此时第4个串行进入等待;
08-16 20:38:41.211 26282-26353/com.example.administrator.singletoptest E/AsynTask: finished
08-16 20:38:41.213 26282-26354/com.example.administrator.singletoptest E/AsynTask: finishedCon
//1700,不再分析
08-16 20:38:41.415 26282-26346/com.example.administrator.singletoptest E/AsynTask: finishedCon
08-16 20:38:41.616 26282-26347/com.example.administrator.singletoptest E/AsynTask: finishedCon
08-16 20:38:41.712 26282-26353/com.example.administrator.singletoptest E/AsynTask: finished
08-16 20:38:41.816 26282-26349/com.example.administrator.singletoptest E/AsynTask: finishedCon
08-16 20:38:42.019 26282-26350/com.example.administrator.singletoptest E/AsynTask: finishedCon
08-16 20:38:42.213 26282-26353/com.example.administrator.singletoptest E/AsynTask: finished
08-16 20:38:42.714 26282-26353/com.example.administrator.singletoptest E/AsynTask: finished
08-16 20:38:43.216 26282-26353/com.example.administrator.singletoptest E/AsynTask: finished
08-16 20:38:43.718 26282-26353/com.example.administrator.singletoptest E/AsynTask: finished
08-16 20:38:44.220 26282-26353/com.example.administrator.singletoptest E/AsynTask: finished
08-16 20:38:44.721 26282-26353/com.example.administrator.singletoptest E/AsynTask: finished
总结:
1、AsyncTask,默认的两个线程池可以用一个newSingleThreadExecutor 单任务线程池代替
2、使用两个线程池,可以做到需要串行的任务保持串行提交任务,不需要串行完成的任务可以插队进行并行提交;
3、串行的任务只需要SERIAL_EXECUTOR提交的任务完成即可准备执行,不需要等待并行提交的任务完成;