Message(Message Pool)原始碼分析

許佳佳233發表於2017-11-03

前提概要

筆者有一段時間寫Message一直這麼寫:

Message msg=new Message();
msg.what=0;
handler.sendMessage(msg);

但是事實上,為了提高效率,我們應該複用Message:

Message msg=handler.obtainMessage();
msg.what=0;
handler.sendMessage(msg);

那麼在這個obtainMessage()中究竟是如何實現Message的複用的呢?
儲存結構是怎樣,執行緒併發如何處理等。

原始碼解析

獲取邏輯

首先由obtainMessage()為入口,然後可以即進入到Message.obtain()方法:

    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }
    public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;

        return m;
    }
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    private static final Object sPoolSync = new Object();
    private static Message sPool;

從obtain()原始碼中我們可以看到,所謂的MessagePool,不過就是一個連結串列。

對執行緒併發的處理也便是用synchronized 對sPoolSync 這個final物件加鎖。
而此處為什麼不用物件鎖或者類鎖呢?
由於是靜態方法,物件可能不存在,所以不能用物件鎖。
用類鎖雖然也可以實現,但是MessagePool的邏輯和Message類本身關係不大,用了一方面不是很恰當,另一方面也限制了Message類的擴充。

回收邏輯

獲取的邏輯基本就這樣了,再看下回收的邏輯,這裡我們直接看到MessageQueue.removeMessages()和其中呼叫到的Message.recycleUnchecked():

    void removeMessages(Handler h, int what, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h && p.what == what
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

可以看到,recycleUnchecked()就是Message中另一處呼叫到synchronize(sPoolSync)的地方。對所謂“MessagePool”的處理也就這兩處。recycleUnchecked()中的邏輯便是把Message中的內容清空。
在MessageQueue中removeMessage的邏輯非常簡單,首先把要刪除的Message清空,然後把連結串列中後面的節點放到前面來。(並沒有刪除物件,只是清空了內容放到連結串列後面而已)

相關文章