ThreadLocal源碼解析

ThreadLocal的原理核心就是理順Thread,ThreadLocal以及ThreadLocalMap三者之間的關係。即每個Thread對象中都持有一個ThreadLocalMap成員變量,ThreadLocalMap可以持有多個ThreadLocal和對應的value。當往ThreadLocalMap 設置值時候,key是threadLocal本身。

  • 每個Thread對象中都持有一個ThreadLocalMap成員變量
  • ThreadLocalMap可以持有多個ThreadLocal和對應的value
  • ThreadLocal源碼解析

    下面,通過對其核心的三個方法的流程來理解其實現過程。

    initialValue()方法處理流程分析

    initialValue()方法會返回當前線程對應的“初始值”,這是一個延遲加載的方法,只有在調用get的時候,才會觸發當線程第一次使用get方法訪問變量時,將調用此方法。但是如果線程調用了set方法,在這種情況下,不會調用initialValue方法了。

    <code>protected T initialValue() {

        return null;

    }/<code>

    默認的initialValue方法是沒做任何事情的,所以我們要重寫initialValue方法,就像前面的例子。

    Set流程分析

    Set方法是設置值。

    Threadlocal.set()

    <code>public void set(T value) {
         //獲取當前線程
    Thread t = Thread.currentThread();
    //通過當前線程,獲取當前線程中的ThreadLocalMap
        ThreadLocalMap map = getMap(t);

        if (map != null)
    //如果ThreadLocalMap已經存在,則將值傳進去
            map.set(this, value);
        else
    //如果ThreadLocalMap不存在,則創建ThreadLocalMap
            createMap(t, value);
    }/<code>

    這裡設置值是設置到Thread的ThreadLocalMap中,所以需要獲取當前的Thread。

    Threadlocal.getMap方法

    <code>ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
    }/<code>

    這個方法很簡單,就是獲取線程中的成員變量ThreadLocalMap

    在Thread中成員變量threadLocals就是ThreadLocal.ThreadLocalMap 類型,初始值為null。

    Threadlocal.createMap方法

    <code>void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
    }/<code>

    可以看到,createMap方法就是為Thread的成員變量threadLocals 創建實例。並將需要設置的值放進map中。key就是threadlocal本身,value是需要保存的值。

    Get流程分析

    Get獲取設置的值

    ThreadLocal.get方法

    <code>public T get() {
    //獲取當前的線程
    Thread t = Thread.currentThread();
    //通過當前線程,獲取當前線程中的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    if (map != null) {
    //如果ThreadLocalMap不為空,獲取值
    ThreadLocalMap.Entry e = map.getEntry(this);
    if (e != null) {
    @SuppressWarnings("unchecked")
    T result = (T)e.value;
    return result;
    }
    }
    //如果ThreadLocalMap為空,返回初始值
    return setInitialValue();
    }/<code>

    這裡要注意的是Entry 繼承了弱引用類型,使用弱引用類型的目的是為了避免已經無用的數據佔用內存空間。當一個對象僅僅被weak reference指向, 而沒有任何其他強引用指向, GC運行時候這個對象就會被回收。

    Threadlocal.Entry 類型

    <code>static class Entry extends WeakReference<threadlocal>> {
    /** The value associated with this ThreadLocal. */
    Object value;
    Entry(ThreadLocal> k, Object v) {
    super(k);
    value = v;
    }
    }/<threadlocal>/<code>
    <code>弱引用也是關鍵的知識。下面的代碼可以測試弱引用是否有強引用時候的區別 

    public class TestWeakReference {
    public static void main(String[] args) {
    Car car = new Car(22000,"silver");
    WeakReference weakCar = new WeakReference(car);
    int i=0;
    while(true){
    if(weakCar.get()!=null){
    i++;
    System.out.println("Object is alive for "+i+" loops - "+weakCar);
    }else{
    System.out.println("Object has been collected.");
    break;
    }
    }
    //如果有下面這一句,car就不會被回收。因為被強應用指向了
    //System.out.println(car);
    }
    }
    /<code>

    如果註釋掉打印“System.out.println(car)”這一行,過了一段時間GC後,會獲取到null的car值,然後會打印“Object has been collected.”



    分享到:


    相關文章: