ThreadLocal分析

ThreadLocal介紹

ThreadLocal類用來提供線程內(nèi)部的局部變量。這些變量在多線程環(huán)境下訪問(通過get或set方法訪問)時能保證各個線程里的變量相對獨立于其他線程內(nèi)的變量,ThreadLocal實例通常來說都是private static類型。

只要線程處于活動狀態(tài)就能夠訪問到ThreadLocal實例,在一個線程消失之后,所有線程本地實例副本都會被垃圾收集器收集,除非存在對這些副本的其他引用。

實現(xiàn)原理

ThreadLocal可以看成是一個容器,只是存在的變量是當前線程的而已。

[圖片上傳失敗...(image-eeace1-1530195633300)]

它提供了三個對外的方法分別是 set(T) 、get()、remove()

ThreadLocalMap對象

ThreadLocal是的實現(xiàn)都是基于ThreadLocalMap來處理的。

ThreadLocalMap實現(xiàn)了一個定制化的Map數(shù)據(jù)結構的對象。

[圖片上傳失敗...(image-dd9d9-1530195633300)]

ThreadLocalMap初始化

創(chuàng)建的時候會初始化用于存儲ThreadLocal對象的數(shù)組,
初始化的數(shù)組長度為16,這個數(shù)組對象會被當前線程所共享。

如果一個線程所持有的ThreadLocal對象超過16個會進行重新hash并進行擴容。

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是一個弱引用對象,使用ThreadLocal作為建。

如果一個ThreadLocal沒有被其他任何強引用指向時,如果GC運行這個對象就會被回收。

這樣能夠保證,如果使用ThreadLocal的線程被銷毀時,ThreadLocal也會被回收。


   static class Entry extends WeakReference<ThreadLocal<?>> {
       Object value;
       Entry(ThreadLocal<?> k, Object v) {
           super(k);
           value = v;
       }
   }
    

set方法


public void set(T value) {
    // 獲取當前所在的線程
    Thread t = Thread.currentThread();
    // 獲取當前所在線程的ThreadLocalMap對象
    ThreadLocalMap map = getMap(t);
    // 如果存在直接塞值,如果不存在進行創(chuàng)建再塞值
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

get方法


public T get() {
    // 獲取當前所在的線程
    Thread t = Thread.currentThread();
    // 獲取當前所在線程的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;
        }
    }
    // 如果上面的代碼沒有走通,說明沒有找到值,會塞一個空值進去
    return setInitialValue();
}

private T setInitialValue() {
    // initialValue這個返回的是一個null
    T value = initialValue();
    // 進行創(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() {
     // 獲取當前線程對應的map對象,然后移除
     ThreadLocalMap m = getMap(Thread.currentThread());
     if (m != null)
         m.remove(this);
}
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容