(注意:本文基於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的能力)