浅谈ThreadLocal
ThreadLocal介绍
ThreadLocal顾名思义,线程本地,即各个线程互不干扰的空间,每个线程只能看到当前线程放入的对象。
如下以泛型类型为String的类型为例,分析其内部结构图。
ThreadLocal<String> tl = new ThreadLocal<>();
tl.set("hellowThread");
有上图可以看出,放入ThreadLocal容器中的元素其实是放到该线程的成员变量threadlocals中的,其本质是一个Map,key存的是当前ThreadLocal对象,value存的是真实的对象。
public class ThreadLocal<T> {
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
createMap(t, value);
}
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
}
从上述set()方法和get()方法中都可以看出,都是先获取到Thread对象中的ThreadLocalMap对象,然后对map进行操作的。如此每个线程只能拿到当前线程的成员变量map,因此肯定可以保证线程间互不干扰。
ThreadLocal弱引用问题
弱引用:只要遭遇gc,就回收该引用指向的区域。
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
ThreadLocalMap中的Entry是继承自 WeakReference,也就是说Entry对象中指向ThreadLocal对象的引用是一个弱引用。
这样做的目的是当tl被回收后,使得ThreadLocal对象自动被gc回收,避免内存泄漏。
假设Entry中的key指向ThreadLocal对象的引用是一个强引用,当前线程执行完后会回收其局部变量tl(例如tl = null),此时已经无法访问到该ThreadLocal对象了,但是由于强引用的存在,jvm觉得该ThreadLocal对象不是一个垃圾,因此不会回收,如此会引起内存泄漏问题。使用弱引用时就可以避免该问题,只要强引用tl一断,下次gc就可以回收ThreadLocal这部分内存。
此时还是存在内存泄漏问题,还是接着上述结构,ThreadLocal对象已经被回收了,此时的key为null,因此对于threadlocals中该key所对应的那个value永远就访问不到了,但是由于value强引用的存在,“hellowThread”所占的这部分内存还是得不到回收,因此还是会产生内存泄漏问题。对于该问题的解决方法为用完Threadlocal之后,应该执行其的remove()方法。
- 两年 100 期技术周报后,我收获了这四点
- 如何为技术博客设计一个推荐系统(中):基于 Google 搜索的半自动推荐
- 我是如何为技术博客设计一个推荐系统(上):统计与评分加权
- c#处理空白字符
- 后台优化:使用应用性能管理工具
- Disruptor-NET和内存栅栏
- 我们是如何将 Cordova 应用嵌入到 React Native 中
- ADO.NET的弹性连接控制[ADO.NET idle connection resiliency]
- ASP.Net MVC 5 in Xamarin Studio 5.2
- 自制基于 Snips 和 Snowboy 的智能音箱来保护你的隐私
- 从 React 将从 BSD 改 MIT 许可证,谈如何选择正确的开源许可
- Topshelf 支持Mono 扩展Topshelf.Linux
- 如何在 React Native 实现类微信小程序平台:WebView 调用原生组件
- 如何运营一个开源项目并取得较大影响力?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法