博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
并发之ThreadLocal
阅读量:4480 次
发布时间:2019-06-08

本文共 2343 字,大约阅读时间需要 7 分钟。

ThreadLocal
ThreadLocal 用一种存储变量与线程绑定的方式,在每个线程中用自己的 ThreadLocalMap 安全隔离变量,为解决多线程程序的并发问题提供了一种新的思路。
 
简单画一个UML:

 

 再看下ThreadLocal源码get()与set()
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;}void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);}

 

set(T value):每次获取当前线程,从线程中获取其属性map,然后以当前threadLocal对象作为key,存放value;

get():每次获取当前线程,从线程中获取其属性map,然后以当前threadLocal对象作为key,获取value;

看下原理图:

 

 

从上面的结构图,我们已经窥见ThreadLocal的核心机制:

  • 每个Thread线程内部都有一个Map。
  • Map里面存储线程本地对象(key)和线程的变量副本(value)
  • 但是,Thread内部的Map是由ThreadLocal维护的,由ThreadLocal负责向map获取和设置线程的变量值。
ThreadLocal 弱引用
从上图UML可看出,Entry
static class Entry extends WeakReference
> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal
k, Object v) { super(k); value = v; } }

entry对象中存储了ThreadLocal对象的弱引用和这个ThreadLocal对应的value对象的强引用

 分析:
假设我们在线程的run方法中调用了一个方法,并在这个方法中创建了ThreadLocal对象,并使用了他,内存结构示意图如下。

当这个方法结束时,这个方法中创建的ThreadLocal对象本身(图中绿色区域)就被垃圾回收器回收了,但是线程还没有结束,

所以ThreadLocalMap中还存在这个entry。由于entry中的key(即ThreadLocal对象)是弱引用类型,

所以此时调用entry.get()方法时就会返回null,内部结构如下图所示。

从图中我们可以看到value对象(红色区域)始终不能被回收,而我们再也不会使用它了,这就造成了内存泄露。

那Entry中为什么保存的是key的弱引用呢?其实这是为了最大程度上减少内存泄露,副作用是同时减少哈希表中的冲突。

当ThreadLocal对象被回收时,对应entry中的key就自动变成null(entry对象本身不为null)。若此后我们调用get,set或remove方法时,

就会尝试删除key为null的entry,以释放value对象所占用的内存。

 

总结

  • 每个ThreadLocal只能保存一个变量副本,如果想要上线一个线程能够保存多个副本以上,就需要创建多个ThreadLocal。
  • ThreadLocal内部的ThreadLocalMap键为弱引用,会有内存泄漏的风险。
  • 适用于无状态,副本变量独立后不影响业务逻辑的高并发场景。如果如果业务逻辑强依赖于副本变量,则不适合用ThreadLocal解决,需要另寻解决方案。

参考:

https://www.jianshu.com/p/98b68c97df9b

http://www.cnblogs.com/nullzx/p/7553538.html

 

转载于:https://www.cnblogs.com/xiaozhuanfeng/p/10501093.html

你可能感兴趣的文章
fseek()
查看>>
Python学习笔记——PyQt控件中文字居中显示
查看>>
JAVA环境下利用solrj二次开发SOlR搜索的环境部署常见错误
查看>>
Beta阶段敏捷冲刺前准备
查看>>
mini web框架-3-替换模板
查看>>
Siamese Network简介
查看>>
第六节 MongoDB 状态监控、备份复制及自动分片
查看>>
svg学习(三)rect
查看>>
博客园博文生成章节目录
查看>>
ruby 模块 的引入
查看>>
CI Weekly #21 | iOS 持续集成快速入门指南
查看>>
xml 校验
查看>>
Jquery获取输入框属性file,ajax传输后端,下载图片
查看>>
深入浅出Visual_C动态链接库(Dll)编程(宋宝华)----整理(word)
查看>>
docker运行环境安装-后续步骤(二)
查看>>
Python学习——02-Python基础——【3集合与函数】
查看>>
NPOI导出excel表格应用
查看>>
tensorflow从入门到放弃-0
查看>>
apache和tomcat有什么不同
查看>>
ASP.NET MVC Core的TagHelper(基础篇)
查看>>