線程在Android中是一個很重要的概念,從用途上來說,線程分為主線程和子線程,主線程主要處理和界面相關的事情,而子線程則往往用于執行耗時操作。在Android中扮演線程角色的還有很多,比如AsyncTask和IntentService,同時HandlerThread也是一種特殊的線程,但他們本質都是傳統的線程。AsyncTask底層用到了線程池,對于IntentService和HandlerThread來說,它們的底層則直接使用了線程。
不同形式的線程雖然都是線程,但是它們具有不同的特性和使用場景。AsyncTask封裝了線程池和Handler,它主要是為了友善開發者在子線程中更新UI,HandlerThread是一中消息循環的線程,在它的内部可以使用Handler。IntentService是一個服務,系統對其進行了封裝使其可以更友善地執行背景任務,IntentService内部采用HandlerThread來執行任務,當任務執行完畢後IntentService會自動退出。
在作業系統中,線程是作業系統的排程的最小單元,同時線程又是一種受限的系統資源,即線程不可能無限制地産生,并且線程的建立和銷毀都會相應的開銷。如果一個程序中頻繁地建立和銷毀線程,這顯然不是高效的做法,正确的做法是采用線程池,在這個線程池中會緩存一定數量的線程,通過線程池就可以避免因為頻繁建立和銷毀線程所帶來的系統開銷。
AsyncTask
AsyncTask是一種輕量級的異步任務類,它可以線上程池中執行背景任務,然後把執行的進度和最終結果傳遞給主線程并在主線程中更新UI。從實作上來說,AsyncTask封裝了Thread和Handler,通過AsyncTask可以更加友善地執行背景任務以及在主線程中通路UI,但是AsyncTask并不适合進行特别耗時的背景任務,對于特别耗時的任務來說,用線程池比較好點。
AsyncTask提供了4個核心方法:
onPreExecute(),在主線程中執行,在異步任務執行之前,次方法會被調用,做一些準備工作。
doInBackground(Params…params),線上程池中執行,次方法用于執行異步任務,params參數表示異步任務的輸入參數。
onProgressUpdate(Progress…values),在主線程中執行,當背景任務的執行進度發生改變時此方法會被調用。
onPostExecute(Result result),在主線程中執行,在異步任務執行之後,此方法會被調用。
看下源碼:
從中我們知道了,線程池中線程的數量跟CPU核心多少有關,在一個處理隊列中最多隻有128個,這個并發數超過就會報異常,同時源碼裡也看到,是通過sHandler發送一個MESSAGE_POST_RESULT的消息進行最終處理的。
sHandler是一個靜态的Handler對象,為了能夠将執行環境切換到主線程,這就要求sHandler這個對象必須在主線程中建立。由于靜态成員會在加載類的時候進行初始化,是以這就變相要求AsyncTask的類必須在主線程中加載,否則同一個程序中的AsyncTask都無法正常工作。
還有一點要注意下,從Android 3.0開始,預設情況下AsyncTask是串行執行的。但在Android 3.0之前是并行執行的。
HandlerThread
HandlerThread繼承了Thread,它是一種可以使用Handler的Thread,它的實作很簡單,就在run方法中通過Looper.prepare()來建立消息隊列,并通過Looper.loop()來開啟消息循環,這樣在實際的使用中就允許在HandlerThread中建立Handler。看下源代碼:
IntentService
IntentService是一種特殊的Service,它繼承了Service并且它是一種抽象類,是以必須建立它的子類才能使用IntentService。IntentService可用于執行背景耗時的任務,當任務執行後它會自動停止,同時由于IntentService是服務的原因,這導緻他的優先級比單純的線程要高很多,是以IntentService比較适合執行一些高優先級的背景任務,因為它的優先級高不容易被系統殺死。看下源碼:
線程池的優點:
重用線程池中的線程,避免因為線程的建立和銷毀所帶來的性能開銷。
能有效控制線程池中的最大并發數,避免大量的線程之間因為互相搶占系統資源而導緻的阻塞現象。
能夠對線程進行簡單的管理,并提供定時執行以及指定間隔循環執行等功能。
Android中的線程池的概念來源于Java中的Executor,Executor是一個接口,真正的線程池的實作為ThreadPoolExecutor。ThreadPoolExecutor提供一系列參數來配置線程池,通過不同的參數可以建立不同的線程池,從線程池的功能特性來說,線程池主要分為4類。
ThreadPoolExecutor執行任務時大緻遵循以下規則:
如果線程池中的線程數量未達到核心線程的數量,那麼會直接啟動一個核心線程來執行任務。
如果線程中的線程數量已經達到或者超過核心線程的數量,那麼任務會被插入到任務隊列中排隊等待執行。
如果在步驟2中無法将任務插入到任務隊列中,這往往是由于任務隊列已經滿了, 這個時候如果線程數量未達到線程池規定的最大值,那麼會立刻啟動一個非核心線程來執行任務。
如果步驟3的中線程數量已經達到線程池規定的最大值,那麼就拒絕執行此任務,ThreadPoolExecutor會調用RejectedExecutionHandler的rejectedExecution方法來通知調用者。
線程池主要有4類:
FixThreadPool:這是一種線程數量固定的線程池,當線程處于空閑的時候,并不會被回收,除非線程池被關閉了。
CachedThreadPool:這是一種線程數量不定的線程池,它隻有非核心線程,并且最大線程數為Integer.MAX_VALUE。
ScheduledThreadPool:它的核心線程數量是固定的,而非核心線程數是沒有限制的,并且當非核心線程閑置時會被立即回收。
SingleThreadExecutor:這類線程池内部隻有一個核心線程,它確定所有的任務都在同一個線程中按順序執行。
源于對掌握的Android開發基礎點進行整理,羅列下已經總結的文章,從中可以看到技術積累的過程。
1,Android系統簡介
2,ProGuard代碼混淆
3,講講Handler+Looper+MessageQueue關系
4,Android圖檔加載庫了解
5,談談Android運作時權限了解
6,EventBus初了解
7,Android 常見工具類
8,對于Fragment的一些了解
9,Android 四大元件之 " Activity "
10,Android 四大元件之" Service "
11,Android 四大元件之“ BroadcastReceiver "
12,Android 四大元件之" ContentProvider "
13,講講 Android 事件攔截機制
14,Android 動畫的了解
15,Android 生命周期和啟動模式
16,Android IPC 機制
17,View 的事件體系
18,View 的工作原理
19,了解 Window 和 WindowManager
20,Activity 啟動過程分析
21,Service 啟動過程分析
22,Android 性能優化
23,Android 消息機制
24,Android Bitmap相關
25,Android 線程和線程池
26,Android 中的 Drawable 和動畫
27,RecylerView 中的裝飾者模式
28,Android 觸摸事件機制
29,Android 事件機制應用
30,Cordova 架構的一些了解
31,有關 Android 插件化思考
32,開發人員必備技能——單元測試