AsyncTask 串行还是并行
明白串行还是并行非常重要,如果是串行,那么如果有多个task,那么后面的task必须要等前面的task任务执行完了才会被执行。
要明白这个问题,那就先来几百个任务试一下
public void dotask(View view) {
for (int i = 0; i < 300; i++) {
new MyAsynctask().execute(i+"");
}
}
class MyAsynctask extends AsyncTask<String, String, String> {
@Override
protected String doInBackground(String... i) {
SystemClock.sleep(1000);
return i[0]+"";
}
@Override
protected void onPostExecute(String s) {
sb.append(s+",");
log.setText(sb.toString());
}
}
在4.1机器上面效果
在2.3上面效果
首先看2.3上面的代码:
public final AsyncTask<Params, Progress, Result> execute(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;
sExecutor.execute(mFuture);//执行器执行一个任务
return this;
}
看到这里就可以明白在2.3系统中,AsyncTask 是并行的,因为不断调用excute会不断忘线程池添加任务。线程池是并行的,所以AsyncTask也就是串行的
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
并且这里的队列大小为128,如果我们连续传入多个任务,就可能导致崩溃,因为可能导致队列的大小超过128,也就崩溃了。。。
再来看api22 的源码
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);//将任务添加到线程池
}
}
}
通过上面的源码可以发现,每次执行完一个任务后,才会调用scheduleNext往线程池里面添加任务,所以即使线程池是并行的,但是我添加任务的时候是串行的,所以api22中的asynctask是串行的,那么线程池其实再多的线程也没用了,反正每次都只有一个任务在里面。
所以2.3源码中是并行,4.0以上肯定是串行。
下面分析,
1、doInBackground为啥在子线程中执行
2、onPostExecute为啥在主线程执行
第一个问题:
查看ThreadPoolExecutor 的public void execute(Runnable command) {方法发现这里传入一个Runnable,那么mFuture也肯定是一个Runnable查看源码接口
FutureTask implements RunnableFuture , RunnableFuture extends Runnable, Future
其实就是线程池来执行Runnnable里面的run方法
每次创建一个task的时候,都会new一个WorkerRunnable和FutureTask,其实就是一层包装
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return doInBackground(mParams);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
Message message;
Result result = null;
try {
result = 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) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
}
这样看来doInBackgroud方法,在call中调用,如果doInBackgroud要在子线程中执行,那么FutureTask的run方法中调用call()方法
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();//在子线程中调用call方法,call方法调用doInBackgroud
...
}
}
最后是
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
private void finishCompletion() {
// assert state > COMPLETING;
...
done();//done方法中通过handler实现切换线程
callable = null; // to reduce footprint
}
第二个问题:在done方法调用中,可以看到是利用handler机制来实现的。(api22)
protected void done() {
Message message;
Result result = null;
try {
result = 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) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
private static class InternalHandler extends Handler {
@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;
case MESSAGE_POST_CANCEL:
result.mTask.onCancelled();
break;
}
}
}