简介
线程本地变量,用于同一线程之间的传递。每一个线程对象都保存在两个ThreadLocalMap,threadLocals和inheritableThreadLocals,后者会继承父线程的本地变量,以ThreadLocal对象为key,取得map里的值。
源码
属性和构造方法
1 // 哈希值 2 private final int threadLocalHashCode = nextHashCode(); 3 4 private static AtomicInteger nextHashCode = 5 new AtomicInteger(); 6 7 private static final int HASH_INCREMENT = 0x61c88647; 8 9 private static int nextHashCode() {10 return nextHashCode.getAndAdd(HASH_INCREMENT);11 }12 13 protected T initialValue() { // 初始值为空14 return null;15 }16 17 public staticThreadLocalwithInitial(Supplier supplier) { // 函数式编程,返回一个ThreadLocal对象18 return new SuppliedThreadLocal<>(supplier);19 }20 21 public ThreadLocal() { // 构造方法22 }
SuppliedThreadLocal
1 static final class SuppliedThreadLocalextends ThreadLocal { 2 3 private final Supplier supplier; 4 5 SuppliedThreadLocal(Supplier supplier) { 6 this.supplier = Objects.requireNonNull(supplier); 7 } 8 9 @Override10 protected T initialValue() {11 return supplier.get();12 }13 }
基本方法
get()
1 public T get() { 2 Thread t = Thread.currentThread(); // 获取当前线程 3 ThreadLocalMap map = getMap(t); // 根据当前线程获取ThreadLocalMap, Thread#threadLocals,子类可重写getMap()方法,比如InheritableThreadLocal, 返回的就是Thread#inheritableThreadLocals 4 if (map != null) { 5 ThreadLocalMap.Entry e = map.getEntry(this); // 以当前ThreadLocal对象为key, 取得value(ThreadLocalMap.Entry) 6 if (e != null) { 7 @SuppressWarnings("unchecked") 8 T result = (T)e.value; // 返回结果 9 return result;10 }11 }12 return setInitialValue(); // 如果map为空,执行初始化13 }
getMap()
1 ThreadLocalMap getMap(Thread t) { // 获得map2 return t.threadLocals;3 }
setInitialValue()
1 private T setInitialValue() { // 设置初始值 2 T value = initialValue(); // 取得初始值 3 Thread t = Thread.currentThread(); // 当前线程 4 ThreadLocalMap map = getMap(t); // 获取map 5 if (map != null) // 不为空,设置value, key为当前对象 6 map.set(this, value); 7 else 8 createMap(t, value); // 否则,创建map 9 return value;10 }
set()
1 public void set(T value) { // 设置值,逻辑同setInitialValue()2 Thread t = Thread.currentThread();3 ThreadLocalMap map = getMap(t);4 if (map != null)5 map.set(this, value);6 else7 createMap(t, value);8 }
remove()
1 public void remove() { // 移除2 ThreadLocalMap m = getMap(Thread.currentThread());3 if (m != null)4 m.remove(this);5 }
创建map(ThreadLocalMap)
1 void createMap(Thread t, T firstValue) { // 创建map(ThreadLocalMap)2 t.threadLocals = new ThreadLocalMap(this, firstValue);3 }4 5 static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { // 继承map值6 return new ThreadLocalMap(parentMap);7 }
ThreadLocalMap
属性
1 static class Entry extends WeakReference> { // 弱引用 2 Object value; 3 4 Entry(ThreadLocal k, Object v) { 5 super(k); 6 value = v; 7 } 8 } 9 10 private static final int INITIAL_CAPACITY = 16; // 初始容量11 12 private Entry[] table; // 数组13 14 private int size = 0; // 大小15 16 private int threshold; // 阈值,长度的2/317 18 private void setThreshold(int len) { // 设置阈值19 threshold = len * 2 / 3;20 }21 22 private static int nextIndex(int i, int len) { // 下一个索引23 return ((i + 1 < len) ? i + 1 : 0); // 长度范围内,加1; 超过范围,024 }25 26 private static int prevIndex(int i, int len) { // 前一个索引27 return ((i - 1 >= 0) ? i - 1 : len - 1); // 长度范围内,减1; 超过范围,len - 128 }
构造方法
1 ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { // 构造方法 2 table = new Entry[INITIAL_CAPACITY]; // 初始化数组,初始容量为16 3 int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); // firstKey的索引 4 table[i] = new Entry(firstKey, firstValue); // 构造Entry(firstKey->firstValue)对象,并置于i索引处 5 size = 1; // 当前大小为1 6 setThreshold(INITIAL_CAPACITY); // 设置阈值 7 } 8 9 private ThreadLocalMap(ThreadLocalMap parentMap) { // 以父ThreadLocalMap构造ThreadLocalMap10 Entry[] parentTable = parentMap.table; // 取得parentMap的table11 int len = parentTable.length; // 取得table长度12 setThreshold(len); // 设置阈值13 table = new Entry[len]; // 创建数组table14 15 for (int j = 0; j < len; j++) {16 Entry e = parentTable[j];17 if (e != null) {18 @SuppressWarnings("unchecked")19 ThreadLocal
基本方法
getEntry()
1 private Entry getEntry(ThreadLocal key) { // 获取entry2 int i = key.threadLocalHashCode & (table.length - 1); // 计算索引3 Entry e = table[i]; // 取得entry4 if (e != null && e.get() == key) // 找到返回5 return e;6 else7 return getEntryAfterMiss(key, i, e); // 否则调用getEntryAfterMiss方法8 }
getEntryAfterMiss()
1 private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) { // 处理碰撞的情况 2 Entry[] tab = table; 3 int len = tab.length; 4 5 while (e != null) { // 若e为空,直接返回null, 否则遍历table 6 ThreadLocal k = e.get(); // 获得key 7 if (k == key) // 若相等,则找到返回 8 return e; 9 if (k == null)10 expungeStaleEntry(i); // 删除过期的Entry对象11 else12 i = nextIndex(i, len); // 计算下一个索引,继续寻找13 e = tab[i];14 }15 return null;16 }
expungeStaleEntry()
1 private int expungeStaleEntry(int staleSlot) { 2 Entry[] tab = table; 3 int len = tab.length; 4 5 tab[staleSlot].value = null; // value置为空 6 tab[staleSlot] = null; // 槽位置为空 7 size--; // size减1 8 9 Entry e;10 int i;11 for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { // 以staleSlot起始,索引与之碰撞的所有槽位,尝试清除无效的元素12 ThreadLocal k = e.get(); // key13 if (k == null) { // 过期,清理14 e.value = null;15 tab[i] = null;16 size--;17 } else {18 int h = k.threadLocalHashCode & (len - 1); // 重新归置元素19 if (h != i) {20 tab[i] = null; // 原来的槽位清空21 while (tab[h] != null) // 以h为始,找空位22 h = nextIndex(h, len);23 tab[h] = e; // 设置元素24 }25 }26 }27 return i;28 }
set()
1 private void set(ThreadLocal key, Object value) { 2 Entry[] tab = table; 3 int len = tab.length; 4 int i = key.threadLocalHashCode & (len - 1); // 计算索引 5 for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { 6 ThreadLocal k = e.get(); 7 if (k == key) { // 命中,更新value, 返回 8 e.value = value; 9 return;10 }11 if (k == null) { // 替换过期的槽位12 replaceStaleEntry(key, value, i);13 return;14 }15 }16 tab[i] = new Entry(key, value); // 找到空位,新建Entry对象17 int sz = ++size; // size加118 if (!cleanSomeSlots(i, sz) && sz >= threshold) // 清理槽位失败,并且当前size大于阈值,调用rehash方法19 rehash();20 }
replaceStaleEntry()
1 private void replaceStaleEntry(ThreadLocal key, Object value, int staleSlot) { 2 Entry[] tab = table; 3 int len = tab.length; 4 Entry e; 5 6 int slotToExpunge = staleSlot; 7 for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len)) // 从当前staleSlot往前找 8 if (e.get() == null) 9 slotToExpunge = i; // 过期槽位起始处,接下来从slotToExpunge清理过期槽位10 11 for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { // 从当前staleSlot往后找12 ThreadLocal k = e.get();13 if (k == key) { // 命中,替换14 e.value = value; // 替换value15 tab[i] = tab[staleSlot]; // 交换i和staleSlot的元素,i槽位处等待被清理16 tab[staleSlot] = e;17 if (slotToExpunge == staleSlot) // 在staleSlot槽位之前没有过期的槽位,将slotToExpunge设置为i(staleSlot之后的槽位,因为staleSlot已经设置了有效的元素)18 slotToExpunge = i;19 cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); // 清理工作20 return;21 }22 if (k == null && slotToExpunge == staleSlot)23 slotToExpunge = i; // 在staleSlot槽位之前没有过期的槽位,将slotToExpunge设置为i(staleSlot之后的槽位,因为staleSlot后面会设置有效的元素)24 }25 tab[staleSlot].value = null; // 置空26 tab[staleSlot] = new Entry(key, value); // 设置新的值27 if (slotToExpunge != staleSlot) // 如果有过期元素,做清理工作28 cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);29 }
cleanSomeSlots()
1 private boolean cleanSomeSlots(int i, int n) { 2 boolean removed = false; 3 Entry[] tab = table; 4 int len = tab.length; 5 do { 6 i = nextIndex(i, len); 7 Entry e = tab[i]; 8 if (e != null && e.get() == null) { // 找到过期元素,执行清理操作 9 n = len;10 removed = true;11 i = expungeStaleEntry(i); // 具体操作还是由expungeStaleEntry完成12 }13 } while ((n >>>= 1) != 0);14 return removed;15 }
rehash()
1 private void rehash() {2 expungeStaleEntries(); // 清理过期的元素3 if (size >= threshold - threshold / 4)4 resize(); // 扩容5 }
expungeStaleEntries()
1 private void expungeStaleEntries() {2 Entry[] tab = table;3 int len = tab.length;4 for (int j = 0; j < len; j++) { // 从槽位0处,尝试清理过期的条目5 Entry e = tab[j];6 if (e != null && e.get() == null)7 expungeStaleEntry(j); // 调用expungeStaleEntry方法8 }9 }
resize()
1 private void resize() { // 扩容 2 Entry[] oldTab = table; 3 int oldLen = oldTab.length; 4 int newLen = oldLen * 2; // 2倍 5 Entry[] newTab = new Entry[newLen]; // 新数组 6 int count = 0; 7 for (int j = 0; j < oldLen; ++j) { 8 Entry e = oldTab[j]; 9 if (e != null) {10 ThreadLocal k = e.get();11 if (k == null) {12 e.value = null; // 帮助GC13 } else {14 int h = k.threadLocalHashCode & (newLen - 1); // rehash15 while (newTab[h] != null) // 碰撞,计算下一个索引(槽位)16 h = nextIndex(h, newLen);17 newTab[h] = e;18 count++;19 }20 }21 }22 23 setThreshold(newLen); // 设置新的阈值24 size = count;25 table = newTab;26 }
remove()
1 private void remove(ThreadLocal key) { 2 Entry[] tab = table; 3 int len = tab.length; 4 int i = key.threadLocalHashCode & (len - 1); 5 for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { 6 if (e.get() == key) { 7 e.clear(); // 移除 8 expungeStaleEntry(i); // 并清理过期槽位 9 return;10 }11 }12 }
行文至此结束。
尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_threadlocal.html