系列目錄: Handler機(jī)制原理
1. HandlerThread介紹
當(dāng)系統(tǒng)有多個(gè)耗時(shí)任務(wù)需要執(zhí)行時(shí)舰罚,每個(gè)任務(wù)都會開啟一個(gè)新線程去執(zhí)行耗時(shí)任務(wù)逮栅,這樣會導(dǎo)致系統(tǒng)多次創(chuàng)建和銷毀線程挺身,從而影響性能挨下。為了解決這一問題蒿囤,Google提供了HandlerThread从隆,HandlerThread是在線程中創(chuàng)建一個(gè)Looper循環(huán)器,讓Looper輪詢消息隊(duì)列果复,當(dāng)有耗時(shí)任務(wù)進(jìn)入隊(duì)列時(shí)陈莽,則不需要開啟新線程,在原有的線程中執(zhí)行耗時(shí)任務(wù)即可据悔,否則線程阻塞传透。
2. 工作原理
- HandlerThread繼承Thread,在Thread開始執(zhí)行時(shí)跟主線程在ActivityThread.main()方法內(nèi)執(zhí)行代碼邏輯類似耘沼,初始化Looper--
Looper.prepare()
,輪詢消息--Looper.loop();
- 初始化Handler時(shí)极颓,使用HandlerThread線程的Looper對象初始化----
new Handler(Looper)
構(gòu)造方法。 - 至于為什么是在子線程內(nèi)執(zhí)行是因?yàn)榇薍andler使用的Looper是子線程創(chuàng)建的群嗤,執(zhí)行message.target.dispatchMessage()也在子線程內(nèi)菠隆,所以最終執(zhí)行的Runnable或者h(yuǎn)andleMessage()也會在子線程內(nèi)。Handler為什么內(nèi)回主線程執(zhí)行也是如此。
3. 使用實(shí)例代碼
// 步驟1:創(chuàng)建HandlerThread實(shí)例對象
// 傳入?yún)?shù) = 線程名字骇径,作用 = 標(biāo)記該線程
HandlerThread mHandlerThread = new HandlerThread("handlerThread");
// 步驟2:啟動線程
mHandlerThread.start();
// 步驟3:創(chuàng)建工作線程Handler & 復(fù)寫handleMessage()
// 作用:關(guān)聯(lián)HandlerThread的Looper對象躯肌、實(shí)現(xiàn)消息處理操作 & 與 其他線程進(jìn)行通信
// 注:消息處理操作(HandlerMessage())的執(zhí)行線程 = mHandlerThread所創(chuàng)建的工作線程中執(zhí)行
Handler workHandler = new Handler( handlerThread.getLooper() ) {
@Override
public boolean handleMessage(Message msg) {
...//消息處理
return true;
}
});
// 步驟4:使用工作線程Handler向工作線程的消息隊(duì)列發(fā)送消息
// 在工作線程中,當(dāng)消息循環(huán)時(shí)取出對應(yīng)消息 & 在工作線程執(zhí)行相關(guān)操作
// a. 定義要發(fā)送的消息
Message msg = Message.obtain();
//消息的標(biāo)識
msg.what = 1;
// b. 通過Handler發(fā)送消息到其綁定的消息隊(duì)列
workHandler.sendMessage(msg);
// 步驟5:結(jié)束線程破衔,即停止線程的消息循環(huán)
mHandlerThread.quit();
4. 源碼分析
4.1 實(shí)例化HandlerThread
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
//當(dāng)前線程持有的Looper對象
Looper mLooper;
private @Nullable Handler mHandler;
// 方式1. 默認(rèn)優(yōu)先級
public HandlerThread(String name) {
// 通過調(diào)用父類默認(rèn)的方法創(chuàng)建線程
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
// 方法2. 自定義設(shè)置優(yōu)先級
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
...
}
HandlerThread類繼承自Thread類
4.2 啟動HandlerThread
@Override
public void run() {
// 1. 獲得當(dāng)前線程的id
mTid = Process.myTid();
// 2. 創(chuàng)建1個(gè)Looper對象 & MessageQueue對象
Looper.prepare();
// 3. 通過持有鎖機(jī)制來獲得當(dāng)前線程的Looper對象
synchronized (this) {
mLooper = Looper.myLooper();
// 發(fā)出通知:當(dāng)前線程已經(jīng)創(chuàng)建mLooper對象成功
// 此處主要是通知getLooper()中的wait()
notifyAll();
}
// 4. 設(shè)置當(dāng)前線程的優(yōu)先級
Process.setThreadPriority(mPriority);
// 5. 在線程循環(huán)前做一些準(zhǔn)備工作
// 該方法實(shí)現(xiàn)體是空的清女,由子類決定是否實(shí)現(xiàn)
onLooperPrepared();
// 6. 進(jìn)行消息循環(huán),即不斷從MessageQueue中取消息 & 派發(fā)消息
Looper.loop();
mTid = -1;
}
run()內(nèi)所做操作和ActivityThread.main()方法內(nèi)所操作的東西大體相類似晰筛。不同的是嫡丙,利用了鎖機(jī)制來保證getLooper()獲取looper正確。
4.3 獲取實(shí)例化Handler要用到的Looper
public Looper getLooper() {
// 若線程不是存活的读第,則直接返回null
if (!isAlive()) {
return null;
}
// 若當(dāng)前線程存活曙博,再判斷線程的成員變量mLooper是否為null
// 直到線程創(chuàng)建完Looper對象后才能獲得Looper對象,若Looper對象未創(chuàng)建成功怜瞒,則阻塞
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
// 此處會調(diào)用wait方法去等待
wait();
} catch (InterruptedException e) {
}
}
}
// 上述步驟run()使用 持有鎖機(jī)制 + notifyAll() 獲得Looper對象后
// 則通知當(dāng)前線程的wait()結(jié)束等待 & 跳出循環(huán)
// 最終getLooper()返回的是在run()中創(chuàng)建的mLooper對象
return mLooper;
}
- 在獲得HandlerThread工作線程的Looper對象時(shí)存在一個(gè)同步的問題:只有當(dāng)線程創(chuàng)建成功 & 其對應(yīng)的Looper對象也創(chuàng)建成功后才能獲得Looper的值父泳,才能將創(chuàng)建的Handler 與 工作線程的Looper對象綁定,從而將Handler綁定工作線程
- 解決方案:即保證同步的解決方案 = 同步鎖吴汪、wait() 和 notifyAll()惠窄,即 在run()中成功創(chuàng)建Looper對象后,立即調(diào)用notifyAll()通知 getLooper()中的wait()結(jié)束等待 & 返回run()中成功創(chuàng)建的Looper對象浇坐,使得Handler與該Looper對象綁定泼掠。
主要功能代碼既是如此,HandlerThread內(nèi)的其他源碼不再做額外分析