爲了方便你們理解,咱們直接看源碼:數組
public class ThreadLocal<T> { ..... }
ThreadLocal是一個範型類,這標誌着ThreadLocal能夠存儲全部數據,做爲存儲數據來講,咱們首先想到的是會對外提供set,get,remove等方法
set方法:this
/** * Sets the value of this variable for the current thread. If set to * {@code null}, the value will be set to null and the underlying entry will * still be present. * * @param value the new value of the variable for the caller thread. */ public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); }
從源碼能夠看出,首先獲取當前線程,而後調用values方法,咱們來看下values方法:spa
/** * Gets Values instance for this thread and variable type. */ Values values(Thread current) { return current.localValues; }
該方法是返回當前線程的一個存儲實類,那ThreadLocal又是什麼呢?上面說過 ThreadLocal是一個線程內部的數據存儲類,經過它能夠在指定的線程中存儲數據,數據存儲之後,只有在指定線程中能夠獲取到存儲的數據。
咱們來看幾個ThreadLocal方法,先回到set方法,獲得values的實類之後會來一個判斷,爲null調用initializeValues(currentThread)線程
Values initializeValues(Thread current) { return current.localValues = new Values(); }
接下來調用value的put方法,咱們想到的應該是往裏面插值,也就是咱們說的put()。code
void put(ThreadLocal<?> key, Object value) { cleanUp(); // Keep track of first tombstone. That's where we want to go back // and add an entry if necessary. int firstTombstone = -1; for (int index = key.hash & mask;; index = next(index)) { Object k = table[index]; if (k == key.reference) { // Replace existing entry. table[index + 1] = value; return; } if (k == null) { if (firstTombstone == -1) { // Fill in null slot. table[index] = key.reference; table[index + 1] = value; size++; return; } // Go back and replace first tombstone. table[firstTombstone] = key.reference; table[firstTombstone + 1] = value; tombstones--; size++; return; } // Remember first tombstone. if (firstTombstone == -1 && k == TOMBSTONE) { firstTombstone = index; } } }
從源碼能夠看出,把values的值傳入到一個table數組的key.reference的下一個下標中,至此,咱們瞭解了Threadlocal的存值過程,首先會獲取當前線程,根據當前線程獲取Values存儲類,該存儲類在該線程是單例的,在調用values存儲類中的put方法,最終將存儲的內容存儲到Values內部類的table數組下標爲key.reference中 。
接下來咱們來看一下取值的方法:對象
public T get() { // Optimized for the fast path. Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this); }
ThreadLocal的get方法的邏輯也比較清晰,它一樣是取出當前線程的localValues對象,若是這個對象爲null那麼就返回初始值,初始值由ThreadLocal的initialValue方法來描述。rem
protected T initialValue() { return null; }
若是localValues對象不爲null,那就取出它的table數組並找出ThreadLocal的reference對象在table數組中的位置,而後table數組中的下一個位置所存儲的數據就是ThreadLocal的值。
接着咱們再來看一下remove的方法實現:get
void remove(ThreadLocal<?> key) { cleanUp(); for (int index = key.hash & mask;; index = next(index)) { Object reference = table[index]; if (reference == key.reference) { // Success! table[index] = TOMBSTONE; table[index + 1] = null; tombstones++; size--; return; } if (reference == null) { // No entry found. return; } } }
到此咱們就明白ThreadLocal原理了:經過ThreadLocal的set和get方法能夠看出,它們所操做的對象都是當前線程的localValues對象的table數組,所以在不一樣線程中訪問同一個ThreadLocal的set和get方法,它們對ThreadLocal所作的讀寫操做僅限於各自線程的內部,這就是爲何ThreadLocal能夠在多個線程中互不干擾地存儲和修改數據。源碼