并發編程(6)HandlerThread源碼分析

概述

前面分析了很多并發編程方面的東西,但是都是Java層面的,其實Google原生也提供了一些類方便我們進行并發編程,比較常見的有HandlerThreadIntentService,AsyncTask,除此之外還有一些第三方框架Volley,Picasso等。

研究這些類以及開源框架的實現,可以讓我們更好地理解并發編程,甚至是自己也可以寫一個異步框架也不是什么難事,下面就來從源碼的角度按照順序來先分析一下HandlerThread。

正文

注釋

Handy class for starting a new thread that has a looper. The looper can then be 
used to create handler classes. Note that start() must still be called.

一個好用的類用于創建一個自帶Looper的線程。這個Looper可以用來創建Handler。注意start()方法必須首先被調用。

看過Handler的源碼都應該比較熟悉,Handler的消息是需要Looper來進行輪詢的,也就是每個Handler創建的時候都需要傳入一個Looper,不過我們平時創建Handler的時候之所以不需要傳入Looper,是因為主線程默認為我們創建了一個looper,當然我們也可以傳入自己的Looper.所以為了避免每次在子線程中創建Handler都需要創建Looper,Google為我們提供了HandlerThread這個類。

成員變量

    int mPriority;//線程優先級
    int mTid = -1;//線程ID
    Looper mLooper;//創建線程的Looper

繼承關系

HandlerThread

繼承關系比較簡單,僅僅繼承自Thread,在內部做了一些封裝。

構造方法

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

這個方法Google都沒有注釋,太簡單了,就是傳入一個線程名稱,然后優先級是默認的優先級0

  public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

構造方法中新加了一個線程優先級

run方法


    @Override
    public void run() {
        //獲取進程ID
        mTid = Process.myTid();
        //Loopr準備
        Looper.prepare();
        //創建Looper
        synchronized (this) {
            mLooper = Looper.myLooper();
          //喚醒所有等待的線程
            notifyAll();
        }
        //設置線程優先級
        Process.setThreadPriority(mPriority);
        //在Looper循環時做一些準備工作
        onLooperPrepared();
        //開啟循環
        Looper.loop();
        mTid = -1;
    }

getLooper

獲取子線程的Looper

  public Looper getLooper() {
       //如果線程已經消亡,就返回null
        if (!isAlive()) {
            return null;
        }
        //如果線程已經創建了,就在此處停留等待Looper創建完成之后
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                  //等待線程被創建
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

quit方法

   public boolean quit() 
        //獲取looper
        Looper looper = getLooper();
        //退出looper
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

quitSafely

   public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

跟quit方法的唯一區別在于looper.quit()變成了looper.quitSafely(),現在具體分析一下這兩個方法的區別

    public void quit() {
        mQueue.quit(false);
    }
    
    public void quitSafely() {
        mQueue.quit(true);
    }

一個傳入了false,一個傳入了true,繼續追蹤

  void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
              //移除消息隊列中延遲的消息
                removeAllFutureMessagesLocked();
            } else {
              //移除消息隊列中所有的消息
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

removeAllFutureMessagesLocked方法

   private void removeAllFutureMessagesLocked() {
        final long now = SystemClock.uptimeMillis();
        Message p = mMessages;
        if (p != null) {
            if (p.when > now) {
                //當消息隊列中中的消息的發送時間大于當前時間
                //就移除該消息
                removeAllMessagesLocked();
            } else {
                Message n;
                for (;;) {
                    n = p.next;
                    if (n == null) {
                        return;
                    }
                    if (n.when > now) {
                        break;
                    }
                    p = n;
                }
                p.next = null;
                do {
                    p = n;
                    n = p.next;
                    p.recycleUnchecked();
                } while (n != null);
            }
        }
    }

所以看到這里,quit跟quidSafely的區別就在于是否移除消息隊列中還未發送也就是延遲的消息。

使用

       //創建mHandlerThread
        mHandlerThread = new HandlerThread("main");
        //獲取HandlerThead中的Looper
        Looper looper = mHandlerThread.getLooper();
        //創建子線程中的Looper
        Handler handler = new Handler(looper);
        //執行耗時操作
        handler.post(new Runnable() {
            @Override
            public void run() {
                //子線程中執行耗時操作
            }
        });
        
        
   //界面銷毀的時候需要銷毀Looper
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();
    }

總結

如果沒有HandlerThread,我們需要手動去創建一個線程,現在HandlerThread可以幫我們簡化這個操作,但是有一點需要注意的是,由于我們的異步操作是存放在Handler的消息隊列中的,所以是串行的,所以只適合并發量較少的耗時操作。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容