ThrealLocal 是一个泛型类,它的定义为 public class ThrealLocal,只要弄清楚 ThrealLocal 的 set() 和 get() 方法就可以明白它的工作原理了。
1、ThrealLocal 的 set() 方法
/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */publicvoidset(T value) {Thread t =Thread.currentThread();ThreadLocalMap map =getMap(t);if (map !=null)map.set(this, value);elsecreateMap(t, value); }
/** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ThreadLocalMapgetMap(Thread t) {returnt.threadLocals; }
publicclassThreadimplementsRunnable {/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals =null;
/** * Set the value associated with key. * * @param key the thread local object * @param value the value to be set */privatevoidset(ThreadLocal<?> key,Object value) {// We don't use a fast path as with get() because it is at// least as common to use set() to create new entries as// it is to replace existing ones, in which case, a fast// path would fail more often than not.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] =newEntry(key, value);int sz =++size;if (!cleanSomeSlots(i, sz)&& sz >= threshold)rehash();}
/** * 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. */staticclassEntryextendsWeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal k,Object v) { super(k); value = v; } } /** * The table, resized as necessary. * table.length MUST always be a power of two. */privateEntry[] table;
2、ThrealLocal 的 get() 方法
上面分析了 ThreadLocal 的 set() 方法,这里分析它的 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 */publicTget() {Thread t =Thread.currentThread();ThreadLocalMap map =getMap(t);if (map !=null) {ThreadLocalMap.Entry e =map.getEntry(this);if (e !=null)return (T)e.value; }returnsetInitialValue(); }
/** * Variant of set() to establish initialValue. Used instead * of set() in case user has overridden the set() method. * * @return the initial value */privateTsetInitialValue() {T value =initialValue();Thread t =Thread.currentThread();ThreadLocalMap map =getMap(t);if (map !=null)map.set(this, value);elsecreateMap(t, value);return value; }
/** * Returns the current thread's "initial value" for this * thread-local variable. This method will be invoked the first * time a thread accesses the variable with the {@link #get} * method, unless the thread previously invoked the {@link #set} * method, in which case the <tt>initialValue</tt> method will not * be invoked for the thread. Normally, this method is invoked at * most once per thread, but it may be invoked again in case of * subsequent invocations of {@link #remove} followed by {@link #get}. * * <p>This implementation simply returns <tt>null</tt>; if the * programmer desires thread-local variables to have an initial * value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be * subclassed, and this method overridden. Typically, an * anonymous inner class will be used. * * @return the initial value for this thread-local */protectedTinitialValue() {returnnull; }