ThreadLocal介紹
ThreadLocal類用來提供線程內(nèi)部的局部變量烦绳。這些變量在多線程環(huán)境下訪問(通過get或set方法訪問)時(shí)能保證各個(gè)線程里的變量相對獨(dú)立于其他線程內(nèi)的變量毫捣,ThreadLocal實(shí)例通常來說都是private static類型。
只要線程處于活動(dòng)狀態(tài)就能夠訪問到ThreadLocal實(shí)例钓株,在一個(gè)線程消失之后戴陡,所有線程本地實(shí)例副本都會(huì)被垃圾收集器收集褂萧,除非存在對這些副本的其他引用稻薇。
實(shí)現(xiàn)原理
ThreadLocal可以看成是一個(gè)容器嫂冻,只是存在的變量是當(dāng)前線程的而已。
[圖片上傳失敗...(image-eeace1-1530195633300)]
它提供了三個(gè)對外的方法分別是 set(T) 塞椎、get()桨仿、remove()
ThreadLocalMap對象
ThreadLocal是的實(shí)現(xiàn)都是基于ThreadLocalMap來處理的。
ThreadLocalMap實(shí)現(xiàn)了一個(gè)定制化的Map數(shù)據(jù)結(jié)構(gòu)的對象案狠。
[圖片上傳失敗...(image-dd9d9-1530195633300)]
ThreadLocalMap初始化
創(chuàng)建的時(shí)候會(huì)初始化用于存儲ThreadLocal對象的數(shù)組服傍,
初始化的數(shù)組長度為16,這個(gè)數(shù)組對象會(huì)被當(dāng)前線程所共享。
如果一個(gè)線程所持有的ThreadLocal對象超過16個(gè)會(huì)進(jìn)行重新hash并進(jìn)行擴(kuò)容骂铁。
private static final int INITIAL_CAPACITY = 16;
private Entry[] table;
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
Entry
Entry是一個(gè)弱引用對象吹零,使用ThreadLocal作為建。
如果一個(gè)ThreadLocal沒有被其他任何強(qiáng)引用指向時(shí)拉庵,如果GC運(yùn)行這個(gè)對象就會(huì)被回收灿椅。
這樣能夠保證,如果使用ThreadLocal的線程被銷毀時(shí)名段,ThreadLocal也會(huì)被回收阱扬。
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
set方法
public void set(T value) {
// 獲取當(dāng)前所在的線程
Thread t = Thread.currentThread();
// 獲取當(dāng)前所在線程的ThreadLocalMap對象
ThreadLocalMap map = getMap(t);
// 如果存在直接塞值,如果不存在進(jìn)行創(chuàng)建再塞值
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
get方法
public T get() {
// 獲取當(dāng)前所在的線程
Thread t = Thread.currentThread();
// 獲取當(dāng)前所在線程的ThreadLocalMap對象
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;
}
}
// 如果上面的代碼沒有走通伸辟,說明沒有找到值,會(huì)塞一個(gè)空值進(jìn)去
return setInitialValue();
}
private T setInitialValue() {
// initialValue這個(gè)返回的是一個(gè)null
T value = initialValue();
// 進(jìn)行創(chuàng)建操作
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
remove方法
public void remove() {
// 獲取當(dāng)前線程對應(yīng)的map對象馍刮,然后移除
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}