1. 程式人生 > >Java ThreadLocal原始碼解析: Thread和ThreadLocal

Java ThreadLocal原始碼解析: Thread和ThreadLocal

之前對TreadLocal有所理解,對原理也有所瞭解,但一直不深入,重新整理,希望藉以加深理解和印象。

在Jdk1.8中,ThreadLocal相關程式碼主要分為三部分:

  • Thread,其中Thread中儲存對ThreadLocal.ThreadLocalMap的引用,作為Thread類的default屬性;
  • ThreadLocal,類似於執行緒中的T和readLocal.ThreadLocalMap的管理類,提供獲取、設定、刪除等管理方法;
  • ThreadLocal.ThreadLocalMap.ThreadLocal,是ThreadLocal的靜態內部內,底層陣列結構的維護類,包含擴容、獲取等功能,是ThreadLocal的底層核心實現。

1. Thread類

/* 本現場的ThreadLocal. */
ThreadLocal.ThreadLocalMap threadLocals = null;

/*
 *  繼承自父類來的ThreadLocal.
 */
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

通過Thread的建構函式可知預設情況下,inheritableThreadLocals會通過父類的threadLocal初始化,除非特別指明不繼承父類的threadLocal。

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
                      …… ……
                    // 如果指明要繼承,並且父執行緒的threadLocal不為空
			        if (inheritThreadLocals && parent.inheritableThreadLocals != null)  
			            // 通過ThreadLocal建立inheritableThreadLocals 
			            this.inheritableThreadLocals =
			                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
			        /* Stash the specified stack size in case the VM cares */
			        this.stackSize = stackSize;			        
					  …… ……
}

小結:每個執行緒中都有兩個屬性,即兩個ThreadLocalMap,其中一個為執行緒自己的,一個是初始化執行緒時,從父執行緒中的拿來建立的,預設如果父執行緒有threadLocal,子執行緒會繼承父執行緒的threadLocal.

2. ThreadLocal類

前文中所說的,ThreadLocal類類似於ThreadLocalMap管理端。ThreadLocal中主要屬性和方法如下圖:
在這裡插入圖片描述
以下是ThreadLocal中核心方法分析:

    // 使用線性探測法進行map的擴容
    private final int threadLocalHashCode = nextHashCode();

    /**
     * 靜態全域性的儲存下一個hash碼
     */
    private static AtomicInteger nextHashCode =
        new AtomicInteger();

    /**
     * hashCode增量
     */
    private static final int HASH_INCREMENT = 0x61c88647;
    
    // 下一個hashCode增加增量
    private static int nextHashCode() {
    	return nextHashCode.getAndAdd(HASH_INCREMENT);
   }
   
   /* 重要邏輯,當執行緒1呼叫ThreadLocal的get()方法時,首先拿到執行緒1的threadLocals屬性,
     * 如果不為空,  通過以當前ThreadLocal為key值獲取ThreadLocal中存放的值。這裡有點繞,
     * 實際相當於,在執行ThreadLocal<String> threadLocal = new ThreadLocal<String>();後,通
     * 過get()方法,將拿到執行緒1中threadLocals通過get()方法以threadLocal為key值的設定的值。
     * /
   public T get() {
        Thread t = Thread.currentThread();  //獲取當前執行緒
        ThreadLocalMap map = getMap(t);  //獲取當前執行緒的ThreadLocalMap, 即那個屬性
        if (map != null) {     // 如果當前執行緒存在ThreadLocal
            ThreadLocalMap.Entry e = map.getEntry(this);   // ThreadLocalMap中以ThreadLocal為key,獲取ThreadLocalMap中存放的值
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;  // 轉化為正確格式,泛型
                return result;
            }
        }
        return setInitialValue();
  }

   /*
    *  setInitialValue和set(T value)內部邏輯類似,只是一個傳了初始值,一個沒有,如果沒傳初始值,則為null
    */
   private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();  // 獲取當前執行緒
        ThreadLocalMap map = getMap(t);   // 拿到當前執行緒的threadLocals,
        if (map != null)
            map.set(this, value);   // 在threadLocalMap中設定key為當前ThreadLocal, value為value的值
        else
            createMap(t, value);  // 建立一個ThreadLocalMap,並把引用賦值給當前執行緒的threadLocals
        return value;
    }

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

  void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);  //為當前執行緒建立一個threadMap
    }
    static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {  //這是個靜態方法,在Thread中呼叫,即如果要繼承父類的threadLocal,將通過這個房間建立
        return new ThreadLocalMap(parentMap);
    }

總結:重要的是ThreadLocal中的get和set方法,get方法將最終拿到當前執行緒的threadLocals,這是一個map,在set的時候以ThreadLocal為key值,實際上是以ThreadLocal的threadLocalHashCode為key值。