Android之AsyncTask源碼分析(第一篇:加載)

(注意:本文基於API 28的源碼分析,API 29上或其他平臺的源碼略有不同)

第一次創建AsyncTask子類對象時,AsyncTask類作爲父類,會被優先加載到內存中,它持有的類變量、靜態代碼塊會在類加載的初始化階段,合併成一個<clinit>(類構造器),該方法會被執行,接下來看看<clinit>中有哪些語句執行

(注意:本文根據AsyncTask中靜態成員的編寫順序敘述)

 

0、AsyncTask類持有的用於輸出日誌的常量

    private static final String LOG_TAG = "AsyncTask";

 

1、用於獲取當前手機平臺的CPU核心(磊哥顯然看過AsyncTask源碼,代碼都一樣……)

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();

 

2、核心線程池的線程總數,注意不管CPU核心有多少,CORE_POOL_SIZE的最大值爲4

    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));

 

3、線程池的線程總數則是CPU核心數乘以2,而後再+1

    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;

 

4、線程存活時間30s

    private static final int KEEP_ALIVE_SECONDS = 30;

 

5、ThreadFactory對象,用於創建Thread對象

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

ThreadFactory爲一個interface、它內部只定義了一個newThread方法,該處通過匿名內部類創建,重寫了newThread方法,在newThread方法內部通過new Thread(Runnable,  String)創建Thread對象,好處是爲AsyncTask創建的每一個Thread對象,都起了名字“AsyncTask #” + 原子類持有的int值,確保線程名字的唯一性(ThreadFactory對象持有的一個AtomicInteger對象mCount)

 

6、基於鏈表的有界阻塞隊列,最大持有128個Runnable,後面看看它會給哪個線程池使用

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

 

7、AsyncTask類持有的第一個線程池

    public static final Executor THREAD_POOL_EXECUTOR;

 

8、靜態代碼塊,創建了一個線程池對象,由THREAD_POOL_EXECUTOR負責持有(見7號知識點)

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

首先創建一個ThreadPoolExecutor對象,由局部變量threadPoolExecutor暫時持有,看下ThreadPoolExecutor構造方法的傳入參數

a、CORE_POOL_SIZE(見2號知識點) 代表核心線程數量

b、MAXIMUM_POOL_SIZE(見3號知識點)代表線程池內的線程最大數量

c、KEEP_ALIVE_SECONDS(見4號知識點)代表核心線程與非核心線程的存活時間(後面解釋爲何代表核心線程的存活時間)

d、TimeUnit.SECONDS 代表線程存活時間的單位,此處單位是秒

e、sPoolWorkQueue(見6號知識點)代表阻塞隊列,它負責持有任務

f、sThreadFactory(見5號知識點)代表線程工廠,它負責創建線程

然後通過threadPoolExecutor的allowCoreThreadTimeOut方法,傳入true,代表核心線程也超時(默認值是false,這樣KEEP_ALIVE_SECONDS就代表核心線程與非核心線程的存活時間)

最終會由AsyncTask的類變量THREAD_POOL_EXECUTOR負責持有

 

9、創建一個SerialExecutor對象,由AsyncTask類的SERIAL_EXECUTOR持有,詳細代碼(見13號知識點)

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

 

10、AsyncTask類持有的兩個常量,後面看看要做什麼

    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

 

11、AsyncTask類持有的sDefaultExecutor,默認指向的是SERIAL_EXECUTOR(見9號知識點)

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

 

12、AsyncTask類持有的一個Handler對象sHandler,Handler機制太重要,無處不見

    private static InternalHandler sHandler;

 

13、靜態內部類

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

a、SerialExecutor對象持有一個ArrayDeque對象mTasks,它是雙端隊列(即能做棧、又能做隊列)、持有一個Runnable對象mActive

b、爲重寫的execute方法,增加了一個synchronized修飾,同一時刻,獲得對象鎖的線程才能執行該方法,目的是爲了共享變量mTasks的插入元素,在同一個時刻只有一個元素插入,在execute方法內部做了兩件事情,第一是調用了mTasks的offer方法,插入了一個Runnable對象,在該Runnable對象重寫的run方法內部,首先調用傳入的Runnable對象r的run方法,然後會一定會執行的scheduleNext()方法,第二是當mActivity爲null,會執行scheduleNext()方法

c、scheduleNext方法,從ArrayDeque對象mTasks取出Runnable對象,交由mActive持有,然後會在成功獲取到任務到情況下,將任務提交到一個線程池裏(見7號知識點),由線程池中的線程負責執行任務

 

14、獲取一個主線程的Handler對象,它的唯一調用處是AsyncTask對象初始化持有的mHandler位置處

    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

 

15、用於變更默認的Executor(hide修飾)

    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

 

總結

a、AsyncTask利用了Java現有的線程池技術

b、AsyncTask類持有一個線程池、由AsyncTask類的THREAD_POOL_EXECUTOR負責持有(一個常量)

c、AsyncTask對象提交的任務是串行執行(默認實現),意味着同一時刻只有一個Runnable會在線程池中執行

e、如果想要同一時刻多個Runnable並行,就需要你調用executeOnExecutor方法,並傳入一個自定義的Executor實現類

f、Executor接口定義了作爲執行者的規範,作者巧妙的實現了一個具備Executor能力的實現類SerialExecutor和線程池ThreadPoolExecutor配合的如此默契,厲害!(注意:實現Executor接口的類,不能算做線程池類,只能說是具備Executor的能力)

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章