Handler的前世今生1——ThreadLocal

1.簡要

有些初級開發者總是認爲Handler是用來更新UI的。這從其主要使用場景上講,是沒有問題的。但是要想更好的去了解Handler及其背後的運行機制,這個認識往往會導致對Handler理解的不夠深刻,可謂是一葉障目,不見泰山。(PS:我在面試過程中,經常會考察面試者對於Handler的認識)

片面認識—— Handler是用來更新UI的。


2. 面試迷茫點

No Looper; Looper.prepare() wasn’t called on this thread.

Only one Looper may be created per thread

上面這兩個異常,有些開發者可能在實際開發工作中都沒有遇到過。究其原因,沒有在子線程中去創建過Handler


這也是有很大一部分面試者,談到Handler的運行機制,用法及注意事項時,能做到侃侃而談。下面列出幾種常見場景:

  1. 當談起多線程通信時,有一些面試者不知所云,但是說Handler,立刻就精神煥發。
  2. 涉及到HandlerThread的存在意義,有些茫然無措。
  3. 涉及到Handler,Thread,Looper,MessageQueue之間的對應關係時,有些說不清楚。

個人認爲,這都是對於Handler的片面認識導致的。


3. Thread 和 Looper的婚姻關係

廢話一句,我還是希望大家能仔細看一下上面的文字…

No Looper; Looper.prepare() wasn’t called on this thread. 不存在Looper——在該線程中沒有調用Looper.prepare()方法。

Only one Looper may be created per thread 一個線程只能創建一個Looper。

從上面的錯誤提示中,我們可以得出一個結論:線程和Looper是1:1對應的關係

我們今天這篇文章主要探討的是:如何保持這種正常的婚姻關係

在Looper類中,你會看到:

ThreadLocal成員變量
 // sThreadLocal.get() will return null unless you've called prepare().
 // 若不調用prepare()方法則返回null
    @UnsupportedAppUsage(只支持APP使用)
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
prepare()方法
// 清楚地看到該變量的set()/get()
 private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        // 注意這裏:新建Looper,我們看看Looper構造函數幹了些什麼
        sThreadLocal.set(new Looper(quitAllowed));
    }
Looper方法
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

是誰在努力維持着這段美好的婚姻(Looper 和 Thread )呢?

Oop, ThreadLocal.


3.淺識ThreadLocal

1. set()方法
 /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value. 給當前線程設置一個指定的值。
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

key-value形式:當前線程爲key,value就是我們傳過來的值。這唯一性就保持住了。So easy…

看見這個ThreadLocalMap,每個人都會猜測,它難道是一個HashMap 或者HashTable,抑或是 CocurrentHashMap。走過去看一下吧。

	/*ThreadLocalMap is a customized hash map suitable only for
     * maintaining thread local values
     * /
  static class ThreadLocalMap {
  }

ThreadLocalMap是一個只適用於維護thread local 的自定義鍵值對。

4. 總結:

  1. Looper 和Thread 是 1V1的關係,其由ThreadLocal來維持關係;
  2. ThreadLocal 內部是由ThreadLocalMap來存儲的,key 就是當前線程。

歡迎繼續收看 :Handler的前世今生2——Looper

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章