1. 程式人生 > >Java高併發程式設計:HandlerThread

Java高併發程式設計:HandlerThread

1. HandlerThread的使用

繼承自Thread,在run()方法中,執行了Looper.prepare()和Looper.loop(),和handler結合使用,實現後臺輪詢執行緒功能

  • start()
  • quit()
  • getLooper()
public class HandlerThreadActivity extends AppCompatActivity {
    private TextView      mTvServiceInfo;
    private HandlerThread mCheckMsgThread;
    private Handler       mCheckMsgHandler;
    private
boolean isUpdateInfo; private static final int MSG_UPDATE_INFO = 0x110; //與UI執行緒相關的handler private Handler mHandler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread_handler); initBackThread();//建立後臺執行緒
mTvServiceInfo = (TextView) findViewById(R.id.id_textview); } @Override protected void onResume() { super.onResume(); isUpdateInfo = true;//開始查詢 mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO); } @Override protected void onPause() { super
.onPause(); isUpdateInfo = false;//停止查詢 mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO); } private void initBackThread() { mCheckMsgThread = new HandlerThread("check-message-coming"); mCheckMsgThread.start(); mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()) { @Override public void handleMessage(Message msg) { checkForUpdate(); if (isUpdateInfo) { mCheckMsgHandler.sendEmptyMessageDelayed( MSG_UPDATE_INFO, 1000); } } }; } //模擬從伺服器解析資料 private void checkForUpdate() { Thread.sleep(1000);//模擬耗時 mHandler.post(new Runnable() { @Override public void run() { String result = "msg"; mTvServiceInfo.setText(result); } }); } @Override protected void onDestroy() { super.onDestroy(); mCheckMsgThread.quit();//釋放資源 } }

2. HandlerThread原始碼

Handler的構造,其實就是在Handler中持有一個指向該Looper.mQueue物件,當handler呼叫sendMessage方法時,其實就是往該mQueue中去插入一個message,然後Looper.loop()就會取出執行

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

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

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

    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

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

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

    public int getThreadId() {
        return mTid;
    }
}

我們要在子執行緒中呼叫Looper.prepare() 為一個執行緒開啟一個訊息迴圈,預設情況下Android中新誕生的執行緒是沒有開啟訊息迴圈的。(主執行緒除外,主執行緒系統會自動為其建立Looper物件,開啟訊息迴圈。) Looper物件通過MessageQueue來存放訊息和事件。一個執行緒只能有一個Looper,對應一個MessageQueue。 然後通過Looper.loop() 讓Looper開始工作,從訊息佇列裡取訊息,處理訊息。

注意:寫在Looper.loop()之後的程式碼不會被執行,這個函式內部應該是一個迴圈,當呼叫mHandler.getLooper().quit()後,loop才會中止,其後的程式碼才能得以執行。

3. HandlerThread的特點

  • HandlerThread將loop轉到子執行緒中處理,說白了就是將分擔MainLooper的工作量,降低了主執行緒的壓力,使主介面更流暢。

  • 開啟一個執行緒起到多個執行緒的作用。處理任務是序列執行,按訊息傳送順序進行處理。HandlerThread本質是一個執行緒,線上程內部,程式碼是序列處理的。

  • 但是由於每一個任務都將以佇列的方式逐個被執行到,一旦佇列中有某個任務執行時間過長,那麼就會導致後續的任務都會被延遲處理。

  • HandlerThread擁有自己的訊息佇列,它不會干擾或阻塞UI執行緒。

  • 對於網路IO操作,HandlerThread並不適合,因為它只有一個執行緒,還得排隊一個一個等著。

4. 參考