ThreadLocal的設計優點在哪?

Vt發表於2020-02-11
ThreadLocal的設計優點在哪?
鎮樓(疫情結束後的你.jpg)

前言

在家辦公 ?,不敢出門 ?,不敢理髮 ?

沒錯,和大家一樣,疫情結束後,我們就是鎮樓圖這個樣子。

並且,你是不是也好幾天沒洗頭了呢?

言歸正傳 ~

本篇文章來源於記憶中的一道題,實現一個 ThreadLocal

筆者第一次碰到這個題的時候,當時可是非常天真,分分鐘寫了一下,結果發現是個低配版,請你也繼續往下看看,有沒有和筆者一樣天真過。

正文

低配 ThreadLocal 實現

在生活中的話,想知道一個東西優點在哪裡,該怎麼辦?

幹說,估計大多數人都聽不懂。 但是,如果有同類產品作比較,那麼優缺就顯而易見了。那麼同樣的,下文中用筆者的低配版MyThreadLocal來看看ThreadLocal有什麼優點。


其實當時看到這題的時候,還沒仔細看過ThreadLocal的原始碼,但是腦中還是有幾個關鍵字的,Map弱引用,於是動手就寫了一個版本, 大體實現是這樣的:

public class ThreadLocal<T> {

    private Map<Thread, T> threadValMap = Collections.synchronizedMap(new WeakHashMap<>());
    
    public void set(T value) {
        threadValMap.put(Thread.currentThread(), value);
    }

    public T get() {
        return threadValMap.get(Thread.currentThread());
    }

    // remove....
}
複製程式碼

你別說,測試了一下,基本功能沒毛病,Thread用完之後消除引用,通知 GC,過一會鍵值也成功被回收。

但是翻開 ThreadLocal 本身的原始碼,設計可是大相徑庭。

這個低配版和正統版有什麼區別?

對比兩個ThreadLocal

上文提到的自己實現的ThreadLocal,下文我就一直稱呼為MyThreadLocal吧。

MyThreadLocal的實現很簡單,藉助synchronizedMap方法實現了一個同步的弱引用HashMap。

ThreadLocal的設計優點在哪?

那麼ThreadLocal內部是怎樣實現的,我也畫了一張簡圖:

ThreadLocal的設計優點在哪?

不同點之一 :效率

由於Thread類中設計時就帶了一行ThreadLocal.ThreadLocalMap threadLocals = null; 作為屬性。

所以,ThreadLocal在賦值的時候,只需要檢查Thread類中的ThreadLocalMap是不是空的,空的就建立一個,不空就接著用。

上面兩段文字描述的就是MyThreadLocalThreadLocal的第一處不同點:

低配版用synchronizedMap做為同步容器,synchronizedMap是同步容器,並不是併發優化容器,原始碼自然是大量的synchronized.

而ThreadLocal並沒有同步操作,而是操作都是隻針對自己當前執行緒進行操作,是天然的執行緒封閉。 用DB設計作為比喻的話,可以大致上類比為這個場景:

“單表加個欄位就完事了,你非要再建個關聯表,還得注意事務問題”

當然了,DB設計是有不同之處的, 這樣效能就高下立判了,同樣我們在單程式編碼時也要注意,巧用不可變物件執行緒封閉,效能要優於同步

不同點之二:Map的Key型別

從上面的圖片可以看到,MyThreadLocal的Map直接用Thread作為Key,而ThreadLocal 的Map用的是自己本身。

上文我也提到了,Thread直接作為弱引用的Key,GC也是成功回收了,那麼區別在哪?

區別就是隻有測試的時候,你才會new Thread();

實際中執行緒交由執行緒池管理,執行緒池內部採用執行緒複用,那麼Thread將一直保持引用,不能被GC掉,可能導致記憶體洩露。

ThreadLocal倒是也有類似的問題,因為大多數情況我們都會使用static引用ThreadLocal,一直保持強引用。好在ThreadLocal提供了remove方法,只需開發者注意用完後呼叫即可。

最後

通過當時的筆者寫出的低配版MyThreadLocal, 大概也知道了ThreadLocal優點在哪了,同時也感覺有個細節比較有趣:

ThreadLocalMap內部並沒有使用HashMap做輔助,而且直接手寫了一個HashMap

當時看到ThreadLocalMap的程式碼時,以為大佬們是想秀一下資料結構的功底,實際上,hashMap的誕生要晚於ThreadLocalMap,才是沒有用的原因之一。

想想也是這樣,Doug Lea和Josh Bloch這種級別的,還用秀基本功嗎?...


ThreadLocal的設計優點在哪?

相關文章