ThreadLocal是線程局部變數,其中保存了特定於該線程的值.每個線程都擁有一份獨立的副本值,即每個線程修改變數值不影響其他線程該變數的副本值.這些特定於線程的值保存在Thread對象中,當線程終止後,這些值會作為垃圾回收. 如果沒有看源碼可能會認為ThreadLocal內部的實現方式應該是採用...
ThreadLocal是線程局部變數,其中保存了特定於該線程的值.每個線程都擁有一份獨立的副本值,即每個線程修改變數值不影響其他線程該變數的副本值.這些特定於線程的值保存在Thread對象中,當線程終止後,這些值會作為垃圾回收.
如果沒有看源碼可能會認為ThreadLocal內部的實現方式應該是採用Map容器,保存一個
散列
每次創建的ThreadLocal都有唯一的hashCode值,根據這個值hashCode可以計算變數在散列表中對應的地址.ThreadLocalMap的hash函數方法是將hashCode值和散列表容量大小進行與操作得到變數對應的位置.
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
衝突解決
在散列表中會存在地址衝突問題,即對於不同的hashCode可能會計算得到相同地址.對於這種情況,ThreadLocalMap採用了最簡單的衝突解決方案---從衝突發生的地址d開始,依次探測d的下一個地址,直到找到一個空閑單元為止.
裝填因數
ThreadLocalMap 設置的裝填因數為2/3,當變數個數大於2/3時擴大容器容量再散列.
get和set
ThreadLocal的定義和使用比較簡單,只要聲明一個ThreadLocal變數,那該變數就為每個線程都分配了一個副本.通過set和get方法設置和獲取該線程局部變數值:
ThreadLocal<Integer> integerLocal = new ThreadLocal<Integer>();
integerLocal.set(1);
Integer i = integerLocal.get();
對於以上的set和get方法的實現思路也比較簡單.在set方法中,首先查看當前線程是否初始化了散列表,如果沒有則創建一個散列表(初始化容器大小為16).如果存在則根據hashCode計算變數在散列表的地址並設置值.
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
get方法和set方法相似,如果散列表不存在時則創建一個散列表並設置初始值.
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}