##11.1 主線程和子線程
(1)在Java中默認情況下一個進程只有一個線程,也就是主線程,其他線程都是子線程,也叫工作線程。Android中的主線程主要處理和界面相關的事情,而子線程則往往用于執行耗時操作。線程的創建和銷毀的開銷較大,所以如果一個進程要頻繁地創建和銷毀線程的話,都會采用線程池的方式。
(2)在Android中除了Thread,還有`HandlerThread`、`AsyncTask`以及`IntentService`等也都扮演著線程的角色,只是它們具有不同的特性和使用場景。AsyncTask封裝了線程池和Handler,它主要是為了方便開發者在子線程中更新UI。HandlerThread是一種具有消息循環的線程,在它的內部可以使用Handler。IntentService是一個服務,它內部采用HandlerThread來執行任務,當任務執行完畢后就會自動退出。因為它是服務的緣故,所以和后臺線程相比,它比較不容易被系統殺死。
(3)從Android 3.0開始,系統要求網絡訪問必須在子線程中進行,否則網絡訪問將會失敗并拋出`NetworkOnMainThreadException`這個異常,這樣做是為了避免主線程由于被耗時操作所阻塞從而出現ANR現象。
(4)AsyncTask是一個抽象泛型類,它提供了`Params`、`Progress`、`Result`三個泛型參數,如果task確實不需要傳遞具體的參數,那么都可以設置為`Void`。下面是它的四個核心方法,其中`doInBackground`不是在主線程執行的。
`onPreExecute`、`doInBackground`、`onProgressUpdate`、`onPostResult`
## 11.2 Android中的線程形態
(1)`AsyncTask`的使用過程中的條件限制:
1.AsyncTask的類必須在主線程中加載,這個過程在Android 4.1及以上版本中已經被系統自動完成。
2.AsyncTask對象必須在主線程中創建,`execute`方法必須在UI線程中調用。
3.一個AsyncTask對象只能執行一次,即只能調用一次`execute`方法,否則會報運行時異常。
4.在Android 1.6之前,AsyncTask是串行執行任務的,Android 1.6的時候AsyncTask開始采用線程池并行處理任務,但是從Android 3.0開始,為了避免AsyncTask帶來的并發錯誤,AsyncTask又采用一個線程來串行執行任務。盡管如此,在Android 3.0以及后續版本中,我們可以使用AsyncTask的`executeOnExecutor`方法來并行執行任務。但是這個方法是Android 3.0新添加的方法,并不能在低版本上使用。
(2)AsyncTask的原理
1.AsyncTask中有兩個線程池:`SerialExecutor`和`THREAD_POOL_EXECUTOR`。前者是用于任務的排隊,默認是串行的線程池;后者用于真正執行任務。AsyncTask中還有一個Handler,即`InternalHandler`,用于將執行環境從線程池切換到主線程。AsyncTask內部就是通過InternalHandler來發送任務執行的進度以及執行結束等消息。
2.AsyncTask排隊執行過程:系統先把參數`Params`封裝為`FutureTask`對象,它相當于Runnable;接著將FutureTask交給SerialExecutor的`execute`方法,它先把FutureTask插入到任務隊列tasks中,如果這個時候沒有正在活動的AsyncTask任務,那么就會執行下一個AsyncTask任務,同時當一個AsyncTask任務執行完畢之后,AsyncTask會繼續執行其他任務直到所有任務都被執行為止。
(3)`HandlerThread`就是一種可以使用Handler的Thread,它的實現就是在run方法中通過`Looper.prepare()`來創建消息隊列,并通過`Looper.loop()`來開啟消息循環,這樣在實際的使用中就允許在HandlerThread中創建Handler了,外界可以通過Handler的消息方式通知HandlerThread執行一個具體的任務。HandlerThread的run方法是一個無限循環,因此當明確不需要再使用HandlerThread的時候,可以通過它的`quit`或者`quitSafely`方法來終止線程的執行。HandlerThread的最主要的應用場景就是用在IntentService中。
(4)`IntentService`是一個繼承自Service的抽象類,要使用它就要創建它的子類。IntentService適合執行一些高優先級的后臺任務,這樣不容易被系統殺死。IntentService的`onCreate`方法中會創建HandlerThread,并使用HandlerThread的Looper來構造一個Handler對象ServiceHandler,這樣通過ServiceHandler對象發送的消息最終都會在HandlerThread中執行。IntentService會將Intent封裝到Message中,通過ServiceHandler發送出去,在ServiceHandler的`handleMessage`方法中會調用IntentService的抽象方法`onHandleIntent`,所以IntentService的子類都要是實現這個方法。
##11.3 Android中的線程池
(1)使用線程池的好處:
1.重用線程,避免線程的創建和銷毀帶來的性能開銷;
2.能有效控制線程池的最大并發數,避免大量的線程之間因互相搶占系統資源而導致的阻塞現象;
3.能夠對線程進行簡單的管理,并提供定時執行以及指定間隔循環執行等功能。
(2)`Executor`只是一個接口,真正的線程池是`ThreadPoolExecutor`。ThreadPoolExecutor提供了一系列參數來配置線程池,通過不同的參數可以創建不同的線程池,Android的線程池都是通過`Executors`提供的工廠方法得到的。
(3)ThreadPoolExecutor的構造參數
1.`corePoolSize`:核心線程數,默認情況下,核心線程會在線程中一直存活;
2.`maximumPoolSize`:最大線程數,當活動線程數達到這個數值后,后續的任務將會被阻塞;
3.`keepAliveTime`:非核心線程閑置時的超時時長,超過這個時長,閑置的非核心線程就會被回收;
4.`unit`:用于指定keepAliveTime參數的時間單位,有`TimeUnit.MILLISECONDS`、`TimeUnit.SECONDS`、`TimeUnit.MINUTES`等;
5.`workQueue`:任務隊列,通過線程池的execute方法提交的Runnable對象會存儲在這個參數中;
6.`threadFactory`:線程工廠,為線程池提供創建新線程的功能。它是一個接口,它只有一個方法`Thread newThread(Runnable r)`;
7.`RejectedExecutionHandler`:當線程池無法執行新任務時,可能是由于任務隊列已滿或者是無法成功執行任務,這個時候就會調用這個Handler的`rejectedExecution`方法來通知調用者,默認情況下,`rejectedExecution`會直接拋出一個`rejectedExecutionException`。
(4)ThreadPoolExecutor執行任務的規則:
1.如果線程池中的線程數未達到核心線程的數量,那么會直接啟動一個核心線程來執行任務;
2.如果線程池中的線程數量已經達到或者超過核心線程的數量,那么任務會被插入到任務隊列中排隊等待執行;
3.如果在步驟2中無法將任務插入到的任務隊列中,可能是任務隊列已滿,這個時候如果線程數量沒有達到規定的最大值,那么會立刻啟動非核心線程來執行這個任務;
4.如果步驟3中線程數量已經達到線程池規定的最大值,那么就拒絕執行此任務,ThreadPoolExecutor會調用`RejectedExecutionHandler`的`rejectedExecution`方法來通知調用者。
(5)AsyncTask的THREAD_POOL_EXECUTOR線程池的配置:
1.`corePoolSize`=CPU核心數+1;
2.`maximumPoolSize`=2倍的CPU核心數+1;
3.核心線程無超時機制,非核心線程在閑置時間的超時時間為`1s`;
4.任務隊列的容量為`128`。
(6)Android中常見的4類具有不同功能特性的線程池:
1.`FixedThreadPool`:線程數量固定的線程池,它只有核心線程;
2.`CachedThreadPool`:線程數量不固定的線程池,它只有非核心線程;
3.`ScheduledThreadPool`:核心線程數量固定,非核心線程數量沒有限制的線程池,主要用于執行定時任務和具有固定周期的任務;
4.`SingleThreadPool`:只有一個核心線程的線程池,確保了所有的任務都在同一個線程中按順序執行。
- 前言
- 讀書筆記(1)第1章 Activity的生命周期和啟動模式
- 讀書筆記(2)第2章 IPC機制
- 讀書筆記(3)第3章 View的事件體系
- 讀書筆記(4)第4章 View的工作原理
- 讀書筆記(5)第5章 理解RemoteViews
- 讀書筆記(6)第6章 Android的Drawable
- 讀書筆記(7)第7章 Android動畫深入分析
- 讀書筆記(8)第8章 理解Window和WindowManager
- 讀書筆記(9)第9章 四大組件的工作過程
- 讀書筆記(10)第10章 Android的消息機制
- 讀書筆記(11)第11章 Android的線程和線程池
- 讀書筆記(12)第12章 Bitmap的加載和Cache
- 讀書筆記(13)第13章 綜合技術