publicclassThreadLocal<T> { /** * 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); // 获取线程关联的ThreadLocalMap哈希表 if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); // 获取entry if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return 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(); // 这里其实是返回null Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); // 获取线程关联的ThreadLocalMap哈希表 // 如果ThreadLocalMap存在,则直接插入;不存在,则新建ThreadLocalMap if (map != null) map.set(this, value); else createMap(t, value); return value; }
/** * 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); else createMap(t, value); // 如果 ThreadLocalMap 为空则创建 }
/** * Removes the current thread's value for this thread-local * variable. If this thread-local variable is subsequently * {@linkplain #get read} by the current thread, its value will be * reinitialized by invoking its {@link #initialValue} method, * unless its value is {@linkplain #set set} by the current thread * in the interim. This may result in multiple invocations of the * {@code initialValue} method in the current thread. * * @since 1.5 */ publicvoidremove(){ ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); // 移除 }
/** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t){ // 从 Thread 中获取 threadLocals return t.threadLocals; } /** * 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 */ voidcreateMap(Thread t, T firstValue){ t.threadLocals = new ThreadLocalMap(this, firstValue); } }
staticclassThreadLocalMap{ staticclassEntryextendsWeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; // Entry的key是ThreadLocal对象,并且是一个弱引用 // 当没指向key的强引用后,该key就会被垃圾收集器回收 Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } privatestaticfinalint INITIAL_CAPACITY = 16; private Entry[] table; privateint threshold; // Default to 0 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; // 计算索引下标 int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); // ThreadLocal作为key table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); // 设置扩容阈值为 容量的 * 2/3 } 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();
tab[i] = new Entry(key, value); int sz = ++size; // 如果没有清除entry并且容量到达扩容阈值 if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); } // 将staleSlot位置的脏Entry替换为新Entry(key, value) privatevoidreplaceStaleEntry(ThreadLocal<?> key, Object value, int staleSlot){ Entry[] tab = table; int len = tab.length; Entry e;
// Back up to check for prior stale entry in current run. // We clean out whole runs at a time to avoid continual // incremental rehashing due to garbage collector freeing // up refs in bunches (i.e., whenever the collector runs). // 向前环形遍历找到第一个key为null的Entry, staleEntry 翻译过来就是 脏Entry int slotToExpunge = staleSlot; for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len)) if (e.get() == null) slotToExpunge = i;
// Find either the key or trailing null slot of run, whichever // occurs first // 从staleSlot开始向后环形遍历tab直到tab[i]为空 for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal<?> k = e.get();
// If we find key, then we need to swap it // with the stale entry to maintain hash table order. // The newly stale slot, or any other stale slot // encountered above it, can then be sent to expungeStaleEntry // to remove or rehash all of the other entries in run. if (k == key) { // 如果在向后环形查找过程中发现key相同的Entry就和脏Entry进行交换 e.value = value;
tab[i] = tab[staleSlot]; tab[staleSlot] = e;
// Start expunge at preceding stale entry if it exists // 如果在查找过程中还未发现脏Entry,也就是开始向前环形遍历时没有发现脏Entry // 那么就以当前位置作为cleanSomeSlots的起点 if (slotToExpunge == staleSlot) slotToExpunge = i; // 搜索脏Entry并进行清理 cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); return; }
// If we didn't find stale entry on backward scan, the // first stale entry seen while scanning for key is the // first still present in the run. // 如果向后环形遍历时发现脏Entry,并且之前向前环形遍历时未发现脏Entry, // 后面就以此时这个位置作为起点执行cleanSomeSlots if (k == null && slotToExpunge == staleSlot) slotToExpunge = i; }
// If key not found, put new entry in stale slot //如果在查找过程中没有找到可以覆盖的Entry,则将新的entry插入在脏Entry tab[staleSlot].value = null; tab[staleSlot] = new Entry(key, value);
// If there are any other stale entries in run, expunge them if (slotToExpunge != staleSlot) // 从slotToExpunge位置开始清理脏Entry cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); } // 遍历时发现脏Entry,会调用该方法清除脏Entry,expunge翻译过来就是清除的意思 // 从 staleSlot 开始 privateintexpungeStaleEntry(int staleSlot){ Entry[] tab = table; int len = tab.length;
// Rehash until we encounter null Entry e; int i; //往后环形遍历直到遇到tab[i]为空 for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal<?> k = e.get(); if (k == null) { // 遇到脏Entry,将其清理掉 e.value = null; tab[i] = null; size--; } else { // 处理rehash的情况 int h = k.threadLocalHashCode & (len - 1); if (h != i) { tab[i] = null;
// Unlike Knuth 6.4 Algorithm R, we must scan until // null because multiple entries could have been stale. while (tab[h] != null) h = nextIndex(h, len); tab[h] = e; } } } return i; } // 从数组下标i+1开始清除一些key为null的entry privatebooleancleanSomeSlots(int i, int n){ boolean removed = false; Entry[] tab = table; int len = tab.length; do { i = nextIndex(i, len); Entry e = tab[i]; if (e != null && e.get() == null) { n = len; removed = true; i = expungeStaleEntry(i); } } while ( (n >>>= 1) != 0); // n >>>= 1 相当于 log2(n)次 return removed; } // 获取 Entry 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); } // 从i出找出的元素为空或者与key不相等(可能发生hash冲突), private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e){ Entry[] tab = table; int len = tab.length;
while (e != null) { ThreadLocal<?> k = e.get(); if (k == key) return e; if (k == null) expungeStaleEntry(i); else // 采用线性探测法解决hash冲突 // i = ((i + 1 < len) ? i + 1 : 0) i = nextIndex(i, len); e = tab[i]; } returnnull; } // 移除元素 privatevoidremove(ThreadLocal<?> key){ 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)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } } }
publicThread(){ init(null, null, "Thread-" + nextThreadNum(), 0); } /** * Initializes a Thread with the current AccessControlContext. * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean) */ privatevoidinit(ThreadGroup g, Runnable target, String name, long stackSize){ init(g, target, name, stackSize, null, true); } /** * Initializes a Thread. * * @param g the Thread group * @param target the object whose run() method gets called * @param name the name of the new Thread * @param stackSize the desired stack size for the new thread, or * zero to indicate that this parameter is to be ignored. * @param acc the AccessControlContext to inherit, or * AccessController.getContext() if null * @param inheritThreadLocals if {@code true}, inherit initial values for * inheritable thread-locals from the constructing thread */ privatevoidinit(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals){ if (name == null) { thrownew NullPointerException("name cannot be null"); }
this.name = name;
Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); if (g == null) { /* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager what to do. */ if (security != null) { g = security.getThreadGroup(); }
/* If the security doesn't have a strong opinion of the matter use the parent thread group. */ if (g == null) { g = parent.getThreadGroup(); } }
/* checkAccess regardless of whether or not threadgroup is explicitly passed in. */ g.checkAccess();
/* * Do we have the required permissions? */ if (security != null) { if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } }
g.addUnstarted();
this.group = g; this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); if (security == null || isCCLOverridden(parent.getClass())) this.contextClassLoader = parent.getContextClassLoader(); else this.contextClassLoader = parent.contextClassLoader; this.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext(); this.target = target; setPriority(priority); // inheritThreadLocals 默认为 true,如果 父线程中的inheritableThreadLocals不为空 // 就将其拷贝到子线程中的inheritableThreadLocals if (inheritThreadLocals && parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize;
/* Set thread ID */ tid = nextThreadID(); }
注意:如果父线程中的 inheritableThreadLocal 重新执行了 set 方法,那么子线程执行 get 方法是获取不到父线程中 set 的数据,因为它们是两个不同的引用,和深拷贝浅拷贝无关。