ThreadLocal源码分析:(二)get()方法
在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方法
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); // 获取线程t中的ThreadLocalMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); // 获取entry,见代码1
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue(); // 没有找到对应的值,调用setInitialValue方法并返回初始值,见代码4
}
关键逻辑就是去当前线程的ThreadLocalMap中获取对应此ThreadLocal对象的entry,如果获取到了就返回entry的value。否则返回调用setInitialValue方法的结果。
代码1
ThreadLocal.ThreadLocalMap类的getEntry方法
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key) // 在key计算hash的位置上直接命中查询,直接返回该entry
return e;
else
return getEntryAfterMiss(key, i, e); // 没有直接命中,调用getEntryAfterMiss,见代码2
}
如果在key计算hash的位置上直接命中查询,直接返回该entry,否则调用getEntryAfterMiss并返回结果。
代码2
ThreadLocal.ThreadLocalMap类的getEntryAfterMiss方法
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
while (e != null) { // 从i位置开始遍历,寻找key能对应上的entry
ThreadLocal<?> k = e.get();
if (k == key)
return e;
if (k == null)
expungeStaleEntry(i); // 遇到key为null的entry,调用expungeStaleEntry方法,见代码3
else
i = nextIndex(i, len);
e = tab[i];
}
return null; // 实在没有找到,只能返回null了
}
在从第i个entry向后遍历的过程中,找到对应的key的entry就直接返回,如果遇到key为null的entry,则调用expungeStaleEntry方法进行清理。
代码3
ThreadLocal.ThreadLocalMap类的expungeStaleEntry方法
private int expungeStaleEntry(int staleSlot) {
Entry[] tab = table;
int len = tab.length;
// expunge entry at staleSlot
tab[staleSlot].value = null;
tab[staleSlot] = null;
size--; // 以上代码,将entry的value赋值为null,这样方便GC时将真正value占用的内存给释放出来;将entry赋值为null,size减1,这样这个slot就又可以重新存放新的entry了
// Rehash until we encounter null
Entry e;
int i;
for (i = nextIndex(staleSlot, len); // 从staleSlot后一个index开始向后遍历,直到遇到为null的entry
(e = tab[i]) != null;
i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
if (k == null) { // 如果entry的key为null,则清除掉该entry
e.value = null;
tab[i] = null;
size--;
} else {
int h = k.threadLocalHashCode & (len - 1);
if (h != i) { // key的hash值不等于目前的index,说明该entry是因为有哈希冲突导致向后移动到当前index位置的
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) // 对该entry,重新进行hash并解决冲突
h = nextIndex(h, len);
tab[h] = e;
}
}
}
return i; // 返回经过整理后的,位于staleSlot位置后的第一个为null的entry的index值
}
expungeStaleEntry方法不止清理了staleSlot位置上的entry,还把staleSlot之后的key为null的entry都清理了,并且顺带将一些有哈希冲突的entry给填充回可用的index中。
代码4
ThreadLocal类的setInitialValue方法
private T setInitialValue() {
T value = initialValue(); // initialValue()方法直接返回null
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value); // 调用ThreadLocalMap的set方法
else
createMap(t, value); // 创建新的ThreadLocalMap,并将value添加进去
return value;
}
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来回收内存。
ThreadLocal源码分析:(二)get()方法的更多相关文章
- 并发-ThreadLocal源码分析
ThreadLocal源码分析 参考: http://www.cnblogs.com/dolphin0520/p/3920407.html https://www.cnblogs.com/coshah ...
- ThreadLocal源码分析-黄金分割数的使用
前提 最近接触到的一个项目要兼容新老系统,最终采用了ThreadLocal(实际上用的是InheritableThreadLocal)用于在子线程获取父线程中共享的变量.问题是解决了,但是后来发现对T ...
- Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题
4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...
- Java多线程学习之ThreadLocal源码分析
0.概述 ThreadLocal,即线程本地变量,是一个以ThreadLocal对象为键.任意对象为值的存储结构.它可以将变量绑定到特定的线程上,使每个线程都拥有改变量的一个拷贝,各线程相同变量间互不 ...
- Java并发编程之ThreadLocal源码分析
## 1 一句话概括ThreadLocal<font face="微软雅黑" size=4> 什么是ThreadLocal?顾名思义:线程本地变量,它为每个使用该对象 ...
- 并发编程(四)—— ThreadLocal源码分析及内存泄露预防
今天我们一起探讨下ThreadLocal的实现原理和源码分析.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两 ...
- 【JAVA】ThreadLocal源码分析
ThreadLocal内部是用一张哈希表来存储: static class ThreadLocalMap { static class Entry extends WeakReference<T ...
- 框架-springmvc源码分析(二)
框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...
- 十、Spring之BeanFactory源码分析(二)
Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...
- Vue源码分析(二) : Vue实例挂载
Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...
随机推荐
- djang-tastypie学习整理
quick start: 配置环境(pip install: Python 2.7+ or Python 3.4+ Django 1.8+ python-mimeparse 0.1.4+ (http: ...
- AndroidStudio Frameworks detected: Android framework is detected in the project Configure
出现这个问题应该是文件没有用正确的方式打开. 遇到这种情况,就要去检查下载的这个包的结构. 我的这个文件明显真正的是下面这个文件夹,如果把整个当做一个android文件打开会导致文件结 ...
- 关于Web Audio API的入门
Web Audio API提供了一个简单强大的机制来实现控制web应用程序的音频内容.它允许你开发复杂的混音,音效,平移以及更多. 可以先看一下MDN的这篇文章<Web Audio API的运用 ...
- react-native导航器 react navigation 介绍
开发环境搭建好之后,想要进一步了解react-native,可以先从react-native官网上的电影列表案例入手: https://reactnative.cn/docs/0.51/sample- ...
- 使用Python从Workflowy同步大纲到印象笔记
title: 从Workflowy到印象笔记 toc: true comment: true date: 2018-03-17 10:05:54 tags: ["Python", ...
- epoll 实现回射服务器
epoll是I/O复用模型中相对epoll和select更高效的实现对套接字管理的函数. epoll有两种模式 LT 和 ET 二者的差异在于 level-trigger 模式下只要某个 socket ...
- WordPress彩色背景标签云实现
网上有很多的这种效果,但是却几乎没有什么关于彩色背景标签云的教程,网上讲的基本都是让标签云的字体变成彩色而不是背景,我觉得让字体变成彩色有的标签会看不清楚,而且也没有让背景变成彩色好看.先看看效果: ...
- grub4dos和winsetupfromusb1.4
其实grub4dos也是一个多系统启动盘制作软件,GRUB4DOS 最大的成功之处就是既学习了windows的方便易用,又引入linux的强大功能.http://baike.baidu.com/lin ...
- vue零基础学习--搭建项目
一.script引入(联系使用,小型项目) 直接下载并用 <script> 标签引入,Vue 会被注册为一个全局变量. <script src="https://cdn.j ...
- PHP中文关键词匹配
关键词匹配是比较常见的需求,如留言.弹幕及游戏聊天中的敏感词过滤,都需要对一段文字进行关键词匹配.提取到关键词后,再做进一步处理. 本类借助PHP高效的数组和mbstring扩展,来实现对中文关键词的 ...