为了方便你们理解,咱们直接看源码:数组
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能够在多个线程中互不干扰地存储和修改数据。源码