• AsyncTask源码阅读


      AsyncTask是Android系统封装的多线程工具类。它管理着线程池,控制着合理的执行中的线程的个数。同时,它还提供了,执行前,执行中,执行后的接口,方便线程的管理与使用。

      下面,我们来阅读一下AsyncTask的源码,才疏学浅,不能多么深刻的理解,但相信在阅读过程中,能有一些意想不到的收获。

      

    public abstract class AsyncTask<Params, Progress, Result> {
        private static final String LOG_TAG = "AsyncTask";
    
        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);

      首先,我们可以看到,AsyncTask是一个虚类。成员变量非常多,我们一个一个来认识。

      LOG_TAG没什么好说的。

      CPU_COUNT顾名思义就是当前设备的CPU数量。其中Runtime是让app获取虚拟机运行环境的类,不能直接创建,但可以获取它的引用。我们从中取得可用的处理器有多少。

      接下来的CORE_POOL_SIZE和MAXIMUM_POOL_SIZE即是核心线程数和最大线程数。

      KEEP_ALIVE在ThreadPoolExecutor中有所描述:keepAliveTime when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating。

      然后,是一个静态私有的线程工厂。它负责新建线程,其中mCount 是一个原子Integer。虽然没看后面,但我猜想,由于线程工厂sThreadFactory是静态的,可能会有多个线程来读写这个sThreadFactory.mCount因此,它需要是一个线程安全的原子数。getAndIncrement()是后置递增的方法,效果类似于i++,但它本身是线程安全的,而i++不是线程安全的。通过newThread方法,sThreadFactory即新建了以当前已有线程数为名字的新线程。

      sPoolWorkQueue是一个BlockingQueue(阻塞队列)。即如果队列为空,我的取操作将会被阻塞,直到有元素进入队列为止;如果队列为满,我的写入操作将会被阻塞,直接有元素被取走留出空位为止。其他的则和基本队列一样,遵循FIFO原则。而LinkedBlockingQueue则是在构造方法中可以很方便的确定它的长度。这个作为正在工作的线程队列是一个很合适的数据结构。

     

        public static final Executor SERIAL_EXECUTOR = new 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);
                }
            }
        }

      接下来,AsyncTask定义了一个特殊的Executor并创建了它的实例。看看这个类,我们就会发现,其中有一个容器叫ArrayDeque,用来存放我们的任务。

        它是一个可以调整大小的双端队列

      数组双端队列没有容量限制,使他们增长为必要支持使用。

      它们不是线程安全的;如果没有外部同步。

      不支持多线程并发访问。

      null元素被禁止使用在数组deques。

      它们要比堆栈Stack和LinkedList快。mTasks.offe()的主要作用是从双端队列的尾部insert元素,而mTasks.poll()的作用是从双端队列头部取出元素。

      有了以上补充知识,现在我们来看看这个类到底是如何工作的。当执行器执行任务时,首先,我们将一个新的Runnable推入任务队列中。如果任务当前活动任务为空则执行scheduleNext()方法,执行队列中的下一个任务。在scheduleNext()方法中,我们可以看到代码先从mTasks中poll出队首的任务,如果不为空,则让线程池去执行它。执行的过程是先执行任务本身的工作(即r.run()),执行完成后,执行scheduleNext()去寻找下一个任务。

        private static final int MESSAGE_POST_RESULT = 0x1;
        private static final int MESSAGE_POST_PROGRESS = 0x2;
    
        private static final InternalHandler sHandler = new InternalHandler();
    
        private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
        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;
                }
            }
        }

      这里定义了一个handler,用于接收进行中的线程发回来的消息。主要接收其他线程完成,和其他线程进度通知两类消息。

      我们先来看看AsyncTaskResult类

        @SuppressWarnings({"RawUseOfParameterizedType"})
        private static class AsyncTaskResult<Data> {
            final AsyncTask mTask;
            final Data[] mData;
    
            AsyncTaskResult(AsyncTask task, Data... data) {
                mTask = task;
                mData = data;
            }
        }

      AsyncTaskResult中有两个成员,一个是AsyncTaskResult封装的任务,另一个Data应该是任务的进度。

      result.mTask.finish(result.mData[0])的代码:

      

        private void finish(Result result) {
            if (isCancelled()) {
                onCancelled(result);
            } else {
                onPostExecute(result);
            }
            mStatus = Status.FINISHED;
        }

      任务在取消或结束时会有这样两个方法。方法本身内容是空的,我们可以继承AsyncTask,重写这两个方法满足业务逻辑。

       private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
        private final WorkerRunnable<Params, Result> mWorker;
        private final FutureTask<Result> mFuture;

      FutureTask 

      一个可取消的异步运算,这个类实现了Fututre的接口,可以开始和取消一个运算操作,判断这个操作是否已经完成了,和重新得到运算操作的结果。运算的结果仅仅在运算结束完成后被恢复,get的方法将会阻塞程序,如果这个运算操作还没有完成的话。一旦运算操作完成了,这个操作就不能重新开始或者取消了。

      这个类过去常常用于包装一个Callable or Runnable 类的。因为FutureTask实现了runnable借口,一个FutureTask可以实现线程池中的execution方法。

    除了是一个单独的类之外,这个类还提供了可能有之用途定制任务classed的保护功能.

      

        private final AtomicBoolean mCancelled = new AtomicBoolean();
        private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

      接下面就是两个线程安全的Boolean型,记录任务是否已被取消和任务是否已被调用,两个状态。

        /**
         * Indicates the current status of the task. Each status will be set only once
         * during the lifetime of a task.
         */
        public enum Status {
            /**
             * Indicates that the task has not been executed yet.
             */
            PENDING,
            /**
             * Indicates that the task is running.
             */
            RUNNING,
            /**
             * Indicates that {@link AsyncTask#onPostExecute} has finished.
             */
            FINISHED,
        }

      这里一个枚举型,用来区分任务的状态,未开始、已开始、已完成。

      

      以上AsyncTask的成员变量就阅读完毕。接下来,开始看AsyncTask中的方法。

     

        /** @hide Used to force static handler to be created. */
        public static void init() {
            sHandler.getLooper();
        }
    
        /** @hide */
        public static void setDefaultExecutor(Executor exec) {
            sDefaultExecutor = exec;
        }

      前两个方法比较简单易懂。用@hide做了标记,即外部不可调用,只在内部进行的一些初始化。

      接下来,我们将开始阅读AsyncTask的构造方法。代码不多,却非常重要。

        /**
         * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
         */
        public 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) {
                @Override
                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);
                    }
                }
            };
        }

      这个方法从整体上来看,就是创建了WorkerRunnable和FutureTask两个类的对象。我们先来看WorkerRunnable类的创建:  

            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));
                }
            };

      上面提到WorkerRunnable类满足了Callable的接口,程序在这里实现了它的call方法。先将任务被调用的标志位设为true,然后将当前线程设为后台线程。doInBackground是个虚方法,没有具体实现,交由子类去实现,使用过AsyncTask的都无需多说这一点,将doInBackground的结果给处理结果的方法postResult(Result r),我们来看看postResult(Result r)的实现。  

        private Result postResult(Result result) {
            @SuppressWarnings("unchecked")
            Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                    new AsyncTaskResult<Result>(this, result));
            message.sendToTarget();
            return result;
        }

       代码会用Result建一个AsyncTaskResult对象,将任务和数据保存在一起,然后作为结果用message发送给sHandler。sHandler前面介绍过是一个将任务执行的进度或结果返回的类。以上WorkerRunnable就创建完成了。接下来再看FutureTask的创建过程。

            mFuture = new FutureTask<Result>(mWorker) {
                @Override
                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);
                    }
                }
            };

       postResultIfNotInvoked()方法和postResult()方法几乎一样,只是在调用前,检查了mTaskInvoked的值。如果任务被取消,则会将result设为null。

      接下来看到一个常用的方法

        public final boolean cancel(boolean mayInterruptIfRunning) {
            mCancelled.set(true);
            return mFuture.cancel(mayInterruptIfRunning);
        }

      由于语义化命名,我们非常容易理解,这个方法,即是取消任务。需要传入一个boolean值,表示,如果它正在运行,是否需要中断。

      后面有一些简单的方法比如isCancelled(),就是取前面介绍的mCancelled的值,在此就不赘述了。我们接下来看最核心的方法。execute();

      

         /* <p>This method must be invoked on the UI thread.
         *
         * @param params The parameters of the task.
         *
         * @return This instance of AsyncTask.
         *
         * @throws IllegalStateException If {@link #getStatus()} returns either
         *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
         *
         * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
         * @see #execute(Runnable)
         */
        public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            return executeOnExecutor(sDefaultExecutor, params);
        }

      

      

         /* <p>This method must be invoked on the UI thread.
         *
         * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a
         *              convenient process-wide thread pool for tasks that are loosely coupled.
         * @param params The parameters of the task.
         *
         * @return This instance of AsyncTask.
         *
         * @throws IllegalStateException If {@link #getStatus()} returns either
         *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
         *
         * @see #execute(Object[])
         */
        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;
        }

      方法先做了一个判断,如果任务不是未执行状态,根据任务当前的状态,抛出异常。之后将当前的任务状态改为正在运行,执行 onPreExecute();这个空方法,并将参数传给mWorker,由默认的执行器执行。默认执行器SerialExecutor执行这个任务。这又回到了SerialExecutor的初始化,里面包含了执行任务的方法,这个在前面已经介绍过了。

      到这里,AsyncTask类的基本流程就阅读完毕了。但是里面还有一些类的工作原理不是特别清楚如FutureTask等,有待探究。

      Done!

  • 相关阅读:
    Maven Docker镜像使用技巧
    Dockerfile 最佳实践
    无状态服务
    Docker 镜像加速器
    如何设置Docker容器中Java应用的内存限制
    k8s的容器监测探针
    (部署)使用kubernetes的deployment进行RollingUpdate
    linux下brctl配置网桥
    代码高亮插件
    Docker容器
  • 原文地址:https://www.cnblogs.com/fishbone-lsy/p/5068444.html
Copyright © 2020-2023  润新知