首先,ThreadLocal並非一個Thread,這個類提供了線程局部變量,這些變量不一樣於它們的普通對應物,由於訪問某個變量的每一個線程都有本身的局部變量,它獨立於變量的初始化副本。html
ThreadLocal是如何作到爲每一線程維護變量的副本的呢?下面經過源碼(jdk1.7版本)來闡述ThreadLocal的基本原理。面試
在具體分析以前,先作幾點說明:數組
1:在TreadLocal中有一個靜態內部類ThreadLocalMap函數
static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } } ... }
2:ThreadLocal中又定義一個鍵值對Entry,它用ThreadLocal做爲鍵值。咱們看到在Thread類中有一個ThreadLocalMap的類型的變量叫作threadLocals。this
下面具體分析一下ThreadLocal的兩個關鍵函數get()和set():spa
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }
在get函數中,首先獲取到當前的線程t,再根據t獲取ThreadLocalMap。下面試getMap()函數:線程
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
能夠看到,該函數返回就是咱們上面提到的每一個線程都有的ThreadLocalMap類型變量threadLocals。htm
若是map不爲空,則根據map.getEntry(this)獲取Entry鍵值對。注意:這裏的this指的是當前的ThreadLocal對象,一個Thread可能對應不止一個ThreadLocal,想要知道具體是Thread對應的哪一個ThreadLocal,就要在Thread中維護一個ThreadLocalMap,以ThreadLocal爲鍵,就能夠找到Thread在某個ThreadLocal裏對應的本地數據。獲取到Entry後,咱們就能夠拿到保存在Entry裏面的value值了。對象
private Entry getEntry(ThreadLocal key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); }
若是map爲空,則調用setInitialValue()函數進行初始化。並返回initialValue函數返回的值,不覆寫initialValue的狀況下,返回的是null。blog
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); 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); }
set函數一樣是先獲取ThreadLocalMap類型的變量map。
若是map不爲空,則:
private void set(ThreadLocal key, Object value) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
若是map爲空,則
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
ThreadLocal是經過下面的方式來實現爲每個線程維護變量的副本的:
在ThreadLocal類中定義了一個ThreadLocalMap,每個Thread都有一個ThreadLocalMap類型的變量threadLocals,就是用threadLocals來存儲每個線程的變量副本,threadLocals內部有一個Entry數組,咱們根據鍵值線程對象,來找到對應線程的變量副本。