HandlerThread線程間通信 源碼解析

上一篇我們通過源碼分析了Handler的消息流程原理,如果對(duì)handler的原理還不夠明白的同學(xué)可以先學(xué)習(xí)上篇。我們今天的主角是HandlerThread。此乃我android大軍一員猛將也。

目錄

  • HandlerThread簡(jiǎn)單介紹
  • 如果沒有Handler和HandlerThread以前
  • HandlerThread源碼分析
  • 原生線程間通信

HandlerThread

從名字上來看,這廝肯定和線程有扯不開的關(guān)系。只聞起名還未使用過的同學(xué)別擔(dān)心,我們先說說他的做用,再分析源碼的實(shí)現(xiàn)。

先思考這樣一個(gè)場(chǎng)景,我們知道在android中主線程中是不能做復(fù)雜的耗時(shí)操作。然而可不可以有一種機(jī)制是主線程通知子線程來做某件事呢?

注意: 這里說的是通知子線程來做某件事,不是說在主線程中另起一個(gè)子線程來做某件事。兩者是有區(qū)別的。

這個(gè)還真可以有,并且HandlerThread就是做這件事情的。

首先的確HandlerThread本身就是一個(gè)線程,他的設(shè)計(jì)可以用來將事件流在不同的線程中進(jìn)行切換。恰巧Android主線程可以利用它來做一些耗時(shí)的操作。

如果沒有Handler和HandlerThread以前

我們先來看一個(gè)沒有這種機(jī)制以前是怎么處理的。

下面是偽代碼:

Thread mTh1 =new Thread(()->{
        ·····
    //我做完了,現(xiàn)在想通知mainTh怎么辦???
   });

Thread mainTh=new Thread(()->{
     //做一些事情
        ·····
   //做完了調(diào)用
    mTh1.start();
   });

mainTh.start(); //開始做事

這段代碼很簡(jiǎn)單,我們有兩個(gè)線程,mainTh做完某些事情以后將啟動(dòng)子線程mTh1來執(zhí)行。這些都沒有問題,但當(dāng)mTh1完成任務(wù)以后,它想再次回到主線程中告知mainTh怎么辦?是不是思路瞬間短路了。
為什么?因?yàn)榫€程總是順序執(zhí)行的,而且是并行順序執(zhí)行,一旦執(zhí)行就沒有回路。

當(dāng)HandlerThread出現(xiàn)以后

準(zhǔn)確來說是當(dāng)Handler、Looper、Message、MessageQueue出現(xiàn)以后,HandlerThread基于此。再次提醒讀者先弄清楚Handler通信機(jī)制才能搞明我們下面要分析的。
還是上面這個(gè)功能,我們看偽代碼。

    protected void onCreate(Bundle savedInstanceState) {
     mHThread = new HandlerThread( "mHThread") ;
      mHThread .start();
      mMainHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
            //這里收到的消息將會(huì)在主線程中執(zhí)行

          }
        };

        mHandler = new Handler(mHThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
            //這里收到的消息將會(huì)在mHThread子線程中處理
                        ·····
            //我做完了,現(xiàn)在將消息通知回主線程
             mMainHandler.sendEmptyMessage(2) ;
           }
        };
      
      //主線程做一些事情
        ········
     //做完了調(diào)用mHandler通知子線程mHThread 
       mHandler.sendEmptyMessage(1) ;
}

沒毛病,我們?cè)?code>Activity的onCreate方法中創(chuàng)建了:

  • 兩個(gè) Handler
  • 一個(gè)HandlerThread

我們前面說過HandlerThread其實(shí)就是一個(gè)線程。其中mMainHandler使用了無參構(gòu)造函數(shù),那么它將獲取主線程中的Looper(見Handler源碼)。mHandler傳入了mHThread.getLooper(),即HandlerThread中的子線程中的Looper。兩個(gè)Handler分別持有了主線程的Looper和子線程的Looper。重點(diǎn)就在此處。

然后呢,主線程使用mHandler發(fā)送消息給HandlerThreadLooper進(jìn)行處理。此時(shí)這件事交由子線程來完成。隨后子線程做完事情以后將調(diào)用mMainHandler來通知主線程中的Looper完成主線程中該有的操作。至此順利進(jìn)行了一把線程之間的通信。

HandlerThread源碼分析

為了不占用篇幅,下面的HandlerThread源碼是我精簡(jiǎn)過的,本身源碼也不復(fù)雜。讀者可以自行打開as查看。

public class HandlerThread extends Thread {
    Looper mLooper;

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();//創(chuàng)建Looper
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();//開啟消息輪訓(xùn)
        mTid = -1;
    }
    public Looper getLooper() {  return mLooper;}
    public boolean quit() {    looper.quit();    }
    public boolean quitSafely() {   looper.quitSafely(); }
}

我們可以看到HandlerThread繼承了Thread所以本質(zhì)上它就是一個(gè)普通的線程。那么其中run方法里創(chuàng)建Looper并開啟了循環(huán)隊(duì)列。整個(gè)源碼極其簡(jiǎn)單。前面我的使用場(chǎng)景中就是通過了getLooper方法來獲取當(dāng)前線程中的Looper,所以handler才能在在線程之間將消息靈活的處理。

原生線程間通信

略提一下,拋開Handler在原生Java中其實(shí)也有辦法做線程間通信。只是方法要么不夠優(yōu)雅,要么會(huì)造成cpu運(yùn)算負(fù)荷超高或死鎖等情況。而且經(jīng)常因?yàn)榧夹g(shù)不到位,導(dǎo)致翻車的情況。所以android中的Hanlder通信機(jī)制非常巧妙的避開這樣的問題,提供一下原生方法參考學(xué)習(xí)。

  • 共享內(nèi)存變量 使用同步鎖(容易死鎖)
  • 共享內(nèi)存變量 判斷變量狀態(tài) (極其消耗內(nèi)存)
  • 管道通信

題外話

給各位正在進(jìn)階的同學(xué)們提個(gè)醒,現(xiàn)在大部分工作中都在使用優(yōu)雅的輪子來解決線程切換的問題如rxJava、rxAndroid等,確實(shí)它們非常好用和方便,但不代表handler這種原生的對(duì)象就可以擯棄。那些優(yōu)秀框架的實(shí)現(xiàn)都離不android原生的特性,如果要往上進(jìn)階學(xué)習(xí),就不能只是每天看看這里的大神新出一個(gè)輪子,那里大廠又開源一個(gè)框架,問其原理一概不知,自己去看他們的源碼也是云霧朦朧的。這樣以來自己的技術(shù)深度很難有較大的進(jìn)步。而如果是先從基礎(chǔ)開始早一點(diǎn)摸清他們的套路,再去看人家的框架是怎么寫的。學(xué)習(xí)那些新東西是很快的。而我自己就曾經(jīng)犯下這樣的錯(cuò)誤,走了很多彎路。希望能給各位同學(xué)帶來幫助。愿君與共勉。

下一篇我們將分析IntentService的源碼。


如何下次找到我?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容