ThreadLocal源码分析:(二)get()方法
2018-06-18 02:30:49来源:未知 阅读 ()
在ThreadLocal的get(),set()的时候都会清除线程ThreadLocalMap里所有key为null的value。
而ThreadLocal的remove()方法会先将Entry中对key的弱引用断开,设置为null,然后再清除对应的key为null的value。
本文分析get方法
系列文章链接:
http://www.cnblogs.com/noodleprince/p/8657399.html
http://www.cnblogs.com/noodleprince/p/8658333.html
http://www.cnblogs.com/noodleprince/p/8659028.html
ThreadLocal类的get方法
1 public T get() { 2 Thread t = Thread.currentThread(); 3 ThreadLocalMap map = getMap(t); // 获取线程t中的ThreadLocalMap 4 if (map != null) { 5 ThreadLocalMap.Entry e = map.getEntry(this); // 获取entry,见代码1 6 if (e != null) { 7 @SuppressWarnings("unchecked") 8 T result = (T)e.value; 9 return result; 10 } 11 } 12 return setInitialValue(); // 没有找到对应的值,调用setInitialValue方法并返回初始值,见代码4 13 }
关键逻辑就是去当前线程的ThreadLocalMap中获取对应此ThreadLocal对象的entry,如果获取到了就返回entry的value。否则返回调用setInitialValue方法的结果。
代码1
ThreadLocal.ThreadLocalMap类的getEntry方法
1 private Entry getEntry(ThreadLocal<?> key) { 2 int i = key.threadLocalHashCode & (table.length - 1); 3 Entry e = table[i]; 4 if (e != null && e.get() == key) // 在key计算hash的位置上直接命中查询,直接返回该entry 5 return e; 6 else 7 return getEntryAfterMiss(key, i, e); // 没有直接命中,调用getEntryAfterMiss,见代码2 8 }
如果在key计算hash的位置上直接命中查询,直接返回该entry,否则调用getEntryAfterMiss并返回结果。
代码2
ThreadLocal.ThreadLocalMap类的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) { // 从i位置开始遍历,寻找key能对应上的entry 6 ThreadLocal<?> k = e.get(); 7 if (k == key) 8 return e; 9 if (k == null) 10 expungeStaleEntry(i); // 遇到key为null的entry,调用expungeStaleEntry方法,见代码3 11 else 12 i = nextIndex(i, len); 13 e = tab[i]; 14 } 15 return null; // 实在没有找到,只能返回null了 16 }
在从第i个entry向后遍历的过程中,找到对应的key的entry就直接返回,如果遇到key为null的entry,则调用expungeStaleEntry方法进行清理。
代码3
ThreadLocal.ThreadLocalMap类的expungeStaleEntry方法
1 private int expungeStaleEntry(int staleSlot) { 2 Entry[] tab = table; 3 int len = tab.length; 4 5 // expunge entry at staleSlot 6 tab[staleSlot].value = null; 7 tab[staleSlot] = null; 8 size--; // 以上代码,将entry的value赋值为null,这样方便GC时将真正value占用的内存给释放出来;将entry赋值为null,size减1,这样这个slot就又可以重新存放新的entry了 9 10 // Rehash until we encounter null 11 Entry e; 12 int i; 13 for (i = nextIndex(staleSlot, len); // 从staleSlot后一个index开始向后遍历,直到遇到为null的entry 14 (e = tab[i]) != null; 15 i = nextIndex(i, len)) { 16 ThreadLocal<?> k = e.get(); 17 if (k == null) { // 如果entry的key为null,则清除掉该entry 18 e.value = null; 19 tab[i] = null; 20 size--; 21 } else { 22 int h = k.threadLocalHashCode & (len - 1); 23 if (h != i) { // key的hash值不等于目前的index,说明该entry是因为有哈希冲突导致向后移动到当前index位置的 24 tab[i] = null; 25 26 // Unlike Knuth 6.4 Algorithm R, we must scan until 27 // null because multiple entries could have been stale. 28 while (tab[h] != null) // 对该entry,重新进行hash并解决冲突 29 h = nextIndex(h, len); 30 tab[h] = e; 31 } 32 } 33 } 34 return i; // 返回经过整理后的,位于staleSlot位置后的第一个为null的entry的index值 35 }
expungeStaleEntry方法不止清理了staleSlot位置上的entry,还把staleSlot之后的key为null的entry都清理了,并且顺带将一些有哈希冲突的entry给填充回可用的index中。
代码4
ThreadLocal类的setInitialValue方法
1 private T setInitialValue() { 2 T value = initialValue(); // initialValue()方法直接返回null 3 Thread t = Thread.currentThread(); 4 ThreadLocalMap map = getMap(t); 5 if (map != null) 6 map.set(this, value); // 调用ThreadLocalMap的set方法 7 else 8 createMap(t, value); // 创建新的ThreadLocalMap,并将value添加进去 9 return value; 10 }
setInitialValue方法里面,真正有难度的就是在map不为null时要去调用set方法了。这种情况会在key(也就是ThreadLocal对象)对应的entry已经被清理过后出现,也有可能是一个没有设置过值的ThreadLocal对象来调用get方法,就会进入到这层逻辑。关于ThreadLocalMap的set方法,在另一篇笔记http://www.cnblogs.com/noodleprince/p/8657399.html中有分析过了,这里就不再贴了。
ThreadLocal的get方法,也可能会触发ThreadLocalMap的清理方法,将ThreadLocalMap中key为null的entry给清理掉,方便GC来回收内存。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 你说研究过Spring里面的源码,循环依赖你会么? 2020-06-09
- 深入解析ThreadLocal和ThreadLocalMap 2020-06-08
- 通俗理解spring源码(六)—— 默认标签(import、alias、be 2020-06-07
- 数据结构:用实例分析ArrayList与LinkedList的读写性能 2020-06-04
- 学习源码的第八个月,我成了Spring的开源贡献者 2020-06-02
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash