Android 线程简单分析(一)
Android 并发之synchronized锁住的是代码还是对象(二)
Android 并发之CountDownLatch、CyclicBarrier的简单应用(三)
Android 并发HashMap和ConcurrentHashMap的简单应用(四)(待发布)
Android 并发之Lock、ReadWriteLock和Condition的简单应用(五)
Android 并发之CAS(原子操作)简单介绍(六)
Android 并发Kotlin协程的重要性(七)(待发布)
Android 并发之AsyncTask原理分析(八)
Android 并发之Handler、Looper、MessageQueue和ThreadLocal消息机制原理分析(九)
Android 并发之HandlerThread和IntentService原理分析(十)

相信AsyncTask大家都不陌生。AsyncTask内部封装了线程池和Handler,AsyncTask允许我们在后台进行耗时操作且把结果及时更新到UI上。当然AsyncTask从最开始到现在已经经过了几次代码修改,任务的执行逻辑慢慢地发生了改变,并不是大家所想象的那样:AsyncTask是完全并行执行的就像多个线程一样,其实不是的,所以用AsyncTask的时候还是要注意,下面会一一说明。

AsyncTask到底是串行还是并行?

new MyAsyncTask("MyAsyncTask1").execute("");new MyAsyncTask("MyAsyncTask2").execute("");new MyAsyncTask("MyAsyncTask3").execute("");new MyAsyncTask("MyAsyncTask4").execute("");new MyAsyncTask("MyAsyncTask5").execute("");

看一下日志:

MyAsyncTask1 === 2019-05-03 07:35:23MyAsyncTask2 === 2019-05-03 07:35:26MyAsyncTask3 === 2019-05-03 07:35:29MyAsyncTask4 === 2019-05-03 07:35:32MyAsyncTask5 === 2019-05-03 07:35:35MyAsyncTask6 === 2019-05-03 07:35:38

从5个AsyncTask共耗时15s且时间间隔为3s,很显然是串行执行的。

既然下来我们来分析一下源码:

public abstract class AsyncTask {    private static final String LOG_TAG = "AsyncTask";    // 获取当前CPU数量    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();    // 核心线程数量    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;    //ThreadFactory 线程工厂,通过工厂方法newThread来获取新线程    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());    }};    //阻塞式队列,用来存放待并发执行的任务,初始容量:128个    private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue(128);    /**     * 并发线程池,可以用来并行执行任务,从3.0开始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;}    /**     * 串行任务执行器,其内部实现了串行控制,     * 循环的取出一个个任务交给上述的并发线程池去执行     */    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();    //消息类型:发送结果    private static final int MESSAGE_POST_RESULT = 0x1;    //消息类型:更新进度    private static final int MESSAGE_POST_PROGRESS = 0x2;    /**     * 静态Handler,用来发送上述两种通知,采用UI线程的Looper来处理消息,     * 在Android 5.2之前,AsyncTask必须在UI线程调用,因为子线程     * 默认没有Looper无法创建下面的Handler,程序会直接Crash,但是在5.2之后InternalHandler内部通过     * sHandler = new InternalHandler(Looper.getMainLooper()),所以没必要在UI线程也是可以的     */    private static InternalHandler sHandler;    private final Handler mHandler;    /**     * 默认任务执行器,被赋值为串行任务执行器,AsyncTask变成串行执行任务,SERIAL_EXECUTOR其内部通过     * try {r.run();} finally {scheduleNext();}实现了串行执行。     */    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;    // 这两个就是任务执行体    private final WorkerRunnable mWorker;    private final FutureTask mFuture;    //任务的状态 默认为等待状态,即等待执行,其类型标识为volatile线程可见    private volatile Status mStatus = Status.PENDING;    //原子布尔型,支持高并发访问,标识任务是否被取消    private final AtomicBoolean mCancelled = new AtomicBoolean();    //原子布尔型,支持高并发访问,标识任务是否被执行过    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();    /**     * 串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的     * 目前我们需要知道,asyncTask.execute(Params ...)实际上会调用     * SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候,     * 首先你的task会被加入到任务队列,然后排队,一个个执行。     * 总结:     * 

* 当任务来临时,首先就是入队列,然后判断当前有没有任务正在执行 * 如果没有任务执行则直接调用scheduleNext(),执行任务。 * 当当前任务执行完成又再次在finally块调用scheduleNext执行下一个任务 */ private static class SerialExecutor implements Executor { //线性双向队列,用来存储所有的AsyncTask任务 final ArrayDeque mTasks = new ArrayDeque(); //当前正在执行的AsyncTask任务 Runnable mActive; public synchronized void execute(final Runnable r) { //将新的AsyncTask任务加入到双向队列中 mTasks.offer(new Runnable() { public void run() { try { r.run();//执行AsyncTask任务 } finally { /** * 当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话 * 这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务 */ scheduleNext(); } } }); //如果当前没有任务在执行,直接进入执行逻辑 if (mActive == null) { scheduleNext(); } } //从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行 protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } } public enum Status { /** * 任务等待执行 */ PENDING, /** * 任务正在执行 */ RUNNING, /** * 任务已经执行结束 */ FINISHED, } /** * 在Android 5.2之前,AsyncTask必须在UI线程调用,因为子线程 * 默认没有Looper无法创建下面的Handler,程序会直接Crash,但是在5.2之后InternalHandler内部通过 * sHandler = new InternalHandler(Looper.getMainLooper()),所以没必要在UI线程也是可以的 */ private static Handler getMainHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(Looper.getMainLooper()); } return sHandler; } } private Handler getHandler() { return mHandler; } /** * @hide 设置默认执行器 */ public static void setDefaultExecutor(Executor exec) { sDefaultExecutor = exec; } /** * 创建新的任务,这个方法必须在UI线程中调用,其实在5.2之后工作线程也是可以的 */ public AsyncTask() { this((Looper) null); } /** * 创建新的任务,这个方法必须在UI线程中调用,其实在5.2之后工作线程也是可以的 * * @hide */ public AsyncTask(@Nullable Handler handler) { this(handler != null ? handler.getLooper() : null); } /** * 创建新的任务,这个方法必须在UI线程中调用,其实在5.2之后工作线程也是可以的 * * @hide */ public AsyncTask(@Nullable Looper callbackLooper) { /**构造Handler*/ mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); /**构造任务执行体*/ mWorker = new WorkerRunnable() { 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; } }; /**构造任务执行体,传入mWorker*/ mFuture = new FutureTask(mWorker) { @Override protected void done() { try { //执行Future,通过get获取结果 Result result = get(); postResultIfNotInvoked(result); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; } private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (!wasTaskInvoked) { postResult(result); } } //doInBackground执行完毕,发送消息 private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result;} public final Status getStatus() { return mStatus; } /** * 这个方法是我们必须要重写的,用来做后台计算,使用指定参数通过execute方法执行任务。 * 这个方法能够调用publishProgress方法去更新进度。 * 所在线程:后台线程 */ @WorkerThread protected abstract Result doInBackground(Params... params); /** * 在doInBackground之前调用,用来做初始化工作 * 所在线程:UI线程 */ @MainThread protected void onPreExecute() { } /** * 在doInBackground之后调用,用来接受后台计算结果更新UI * 所在线程:UI线程 */ @SuppressWarnings({"UnusedDeclaration"}) @MainThread protected void onPostExecute(Result result) { } /** * 在publishProgress之后调用,用来更新计算进度 * 所在线程:UI线程 */ @MainThread protected void onProgressUpdate(Progress... values) { } @MainThread protected void onCancelled(Result result) { onCancelled(); } /** * cancel被调用并且doInBackground执行结束,会调用onCancelled,表示任务被取消 * 这个时候onPostExecute不会再被调用,二者是互斥的,分别表示任务取消和任务执行完成 * 所在线程:UI线程 */ @MainThread protected void onCancelled() { } public final boolean isCancelled() { return mCancelled.get(); } public final boolean cancel(boolean mayInterruptIfRunning) { mCancelled.set(true); return mFuture.cancel(mayInterruptIfRunning); } public final Result get() throws InterruptedException, ExecutionException { return mFuture.get(); } public final Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return mFuture.get(timeout, unit); } /** * 这个方法如何执行和系统版本有关,在AsyncTask的使用规则里已经说明,如果你真的想使用并行AsyncTask, * 也是可以的,只要稍作修改 * 必须在UI线程调用此方法,5.2之后这不是必须的 */ @MainThread public final AsyncTask execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } /** * 通过这个方法我们可以自定义AsyncTask的执行方式,串行or并行,甚至可以采用自己的Executor * 为了实现并行,我们可以在外部这么用AsyncTask: * asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params); * 必须在UI线程调用此方法,5.2之后这不是必须的 */ @MainThread public final AsyncTask 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 onPreExecute(); mWorker.mParams = params; //然后后台计算doInBackground才准备开始 exec.execute(mFuture); return this;}/**这是AsyncTask提供的一个静态方法,方便我们直接执行一个runnable*/@MainThreadpublic static void execute(Runnable runnable) { sDefaultExecutor.execute(runnable);}/**打印后台计算进度,onProgressUpdate会被调用*/@WorkerThreadprotected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult(this, values)).sendToTarget(); }}//任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED;}//AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息private static class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); } @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; } }}private static abstract class WorkerRunnable implements Callable { Params[] mParams;}private static class AsyncTaskResult { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }}

AsynTask是如何实现串行的?

public final AsyncTask execute(Params... params) {    return executeOnExecutor(sDefaultExecutor, params);} public final AsyncTask 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    onPreExecute();    mWorker.mParams = params;    //然后后台计算doInBackground才准备开始    exec.execute(mFuture);    return this;}

是不是上面看不出什么来?那是必须的,AsyncTask实现串行是通过控制Executor .execute方法来实现的。

 private static class SerialExecutor implements Executor {    //线性双向队列,用来存储所有的AsyncTask任务    final ArrayDeque mTasks = new ArrayDeque();    //当前正在执行的AsyncTask任务    Runnable mActive;    public synchronized void execute(final Runnable r) {        //将新的AsyncTask任务加入到双向队列中        mTasks.offer(new Runnable() {            public void run() {                try {                    r.run();//执行AsyncTask任务                } finally {                    /**                     * 当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话                     * 这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务                     */                    scheduleNext();                }            }        });        //如果当前没有任务在执行,直接进入执行逻辑        if (mActive == null) {            scheduleNext();        }    }    //从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行    protected synchronized void scheduleNext() {        if ((mActive = mTasks.poll()) != null) {            THREAD_POOL_EXECUTOR.execute(mActive);        }    }}

1、 当任务来临时,首先就是加入队列,然后判断当前有没有任务正在执行;
2、 如果没有任务正在执行则直接调用scheduleNext(),执行任务。
3、 当当前任务执行完成又再次在finally块调用scheduleNext执行下一个任务。这样就实现了串行执行任务,当然串行执行任务也是使用了线程池,那还用说是吧。

那如果我们想要并行,如何操作,很简单之间替换默认的SerialExecutor ,就是因为它,才串行的,所以我们只要像这样就可以实现并行执行任务了:

   new MyAsyncTask("MyAsyncTask1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");

其实AsyncTask源码并不多,文章到此结束,欢迎拍砖。

更多相关文章

  1. Android编程: 调试方法
  2. ListView常用属性、方法
  3. Android多线程(一)
  4. Android 控件(button)对齐方法实现详解
  5. Android Studio更新升级方法
  6. android 实现 APP 保活且正常升级的方法

随机推荐

  1. android 变长数据GSON解析
  2. Android studio 自定义view 画圆
  3. Android隐藏ListView分割线
  4. The Best Android Developer Resources
  5. Android——TextView 富文本之 Clickable
  6. Android 绘制波浪曲线1
  7. Android调试工具及方法
  8. 关于Android 中加入角标显示
  9. Android的静态注册广播问题
  10. Android CTS one function