ThreadLocal类提供的几个方法:
public T get() { } public void set(T value) { } public void remove() { } protected T initialValue() { }
get()方法用来获取ThreadLocal当前线程中保存的变量副本;
set()用来设置当前线程中变量的副本;
remove()用来移除当前线程中变量的副本;
initialValue()是一个protected方法,一般是用来在使用时进行重写,它是一个延迟加载的方法。
首先来看下ThreadLocal类是如何为每个线程创建一个变量的副本的。
先看下get()方法的实现:
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
第一句话是取得当前线程,然后通过getMap(t)方法获取一个ThreadLocalMap类型的map,接着获取到该map中的<key,value>键值对,注意这里获取键值对传进去的是this,而不是当前线程t。(?)
如果获取成功,则返回value;
如果map为空,则调用setInitialValue()方法返回值。
我们来根据上面的每一句来仔细分析:
首先看getMap()方法中做了什么:
/** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
在getMap(t)方法中,是调用当前线程t,返回当前线程t中的一个成员变量threadlocals,注意:这个threadlocals是Thread中的成员变量,而不是ThreadLocal中。
那么我们继续看下Thread类中的成员变量threadlocals是什么:
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
实际上就是一个ThreadLocalMap,这个类型是ThreadLocal当中的一个静态内部类,我们看下ThreadLocalMap的实现:
/** * ThreadLocalMap is a customized hash map suitable only for * maintaining thread local values. No operations are exported * outside of the ThreadLocal class. The class is package private to * allow declaration of fields in class Thread. To help deal with * very large and long-lived usages, the hash table entries use * WeakReferences for keys. However, since reference queues are not * used, stale entries are guaranteed to be removed only when * the table starts running out of space. */ static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
可以看到ThreadLocalMap中的Entry继承了WeakReference,并且使用ThreadLocal作为键值。
然后再继续看setInitialValue()方法的具体实现:
/** * Variant of set() to establish initialValue. Used instead * of set() in case user has overridden the set() method. * * @return the initial value */ 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; }
如果map不为空,就设置键值对;为空,再创建Map,跟下去看createMap()的实现:
/** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @param firstValue value for the initial entry of the map */ void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }