ThreadLocal 原理探究
阿新 • • 發佈:2018-11-29
ThreadLocal 的作用:
This class provides thread-local variables. 提供了執行緒級別的本地變數。
ThreadLocal的原理:
- 每一個執行緒Thread內部維護了兩個package private級別的變數:
- ThreadLocal.ThreadLocalMap threadLocals
- ThreadLocal.ThreadLocalMap inheritableThreadLocals
每一個 ThreadLocal 物件有一個建立時生成唯一的 Id稱為:threadLocalHashCode
private Entry getEntry(ThreadLocal<?> key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); }
- ThreadLocalMap 為一個靜態內部類,包含了一個Entity陣列(Entry[] table)來保持ThreadLocal的執行緒變數;
ThreadLocalMap的原理
- ThreadLocalMap是一個Hash Map,採用的是開放地址法而不是連結串列的方式解決衝突。
- Entry 是 WeakReference 的子類,這樣不再被使用的 ThreadLocal 可以被檢查出來並清除掉。
執行緒隔離的祕密,就在於ThreadLocalMap這個類。ThreadLocalMap是ThreadLocal類的一個靜態內部類,它實現了鍵值對的設定和獲取(對比Map物件來理解),每個執行緒中都有一個獨立的ThreadLocalMap副本,它所儲存的值,只能被當前執行緒讀取和修改。ThreadLocal類通過操作每一個執行緒特有的ThreadLocalMap副本,從而實現了變數訪問在不同執行緒中的隔離。因為每個執行緒的變數都是自己特有的,完全不會有併發錯誤。還有一點就是,ThreadLocalMap儲存的鍵值對中的鍵是this物件指向的ThreadLocal物件,而值就是你所設定的物件了。
ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
神奇的 0x61c88647
待補充;
使用陷阱:
- ThreadLocal和執行緒池同時使用出現變數汙染;
在使用執行緒池的過程中,由於執行緒是不斷的回收和利用故ThreadLocal在伺服器中也是被反覆利用的,在使用中如果不進行清查操作,很容易導致變數汙染。
問題:
❓疑惑1:既然ThreadLocal只維護一個值,每一個Thread中都儲存的是一個副本,為什麼ThreadLocalMap需要時一個數組而不是object呢?
原因:如果我們期望在一個Thread中儲存多個ThreadLocal變數怎麼辦呢?不可能改造Thread,新增一個Object物件吧,所以為了更方便的在同一個Thread中加入多個ThreadLocal變數,才引入了陣列結構,不同的ThreadLocal物件作為不同鍵,所以線上程的ThreadLocalMap物件中設定不同的值。
❓疑惑2:ThreadLocalMap為什麼採用開放地址的方法,而不採用連結串列來防止hash衝突?