ThreadLocal深度解析
本文基于jdk1.8.0_66写成
0. ThreadLocal简介
ThreadLocal可以提供线程内的局部对象,合理的使用可以避免线程冲突的问题
比方说SimpleDateFormat是线程不安全的,但是如果用ThreadLocal给每个线程分配一个SimpleDateFormat对象,我们就可以安全的使用了
为了便于理解,我们可以将ThreadLocal想象成一个Map,key为当前线程,value为存入的值
threadLocal.get() 等效于 map.get(Thread.currentThread())
threadLocal隐式的帮我们完成了获取当前线程的操作,使用起来更为方便
1. naive的想法
如同简介里所说,ThreadLocal最直接的设计思路是:
在ThreadLocal内部维护一个Map,key为当前线程,value为存入的值
ThreadLocal.set(obj)等效于Map.set(Thread.currentThread(), obj)
ThreadLocal.get()等效于Map.get(Thread.currentThread())
这个想法的优点是实现简单,但是问题也很多:
a. 一般来说,一个ThreadLocal会与多个Thread关联,而一个Thread只会与少数的ThreadLocal关联。所以从ThreadLocal去寻找关联的Thread,开销比从Thread寻找关联的ThreadLocal要大。
b. 如果一个Thread死掉了,为了防止内存泄漏,所有ThreadLocal中与这个Thread关联的value都要被释放,这个过程是手动的,不优雅,而且开销较大。
2. JDK1.8中的想法
每个Thread各自维护一个名为threadLocals的变量,其类型为ThreadLocal.ThreadLocalMap
这个Map的key是ThreadLocal,value是关联的值
在调用ThreadLocal.get/set时,先用Thread.currentThread()获得当前Thread,然后找到当前Thread的threadLocals域,再以当前ThreadLocal为key找到对应的value并返回。
这样做好处很多:
a. 一般来说,一个Thread只会与少数的几个ThreadLocal关联,那么从Thread去寻找对应的ThreadLocal开销是很小的
b. 如果一个Thread死掉了,那么它所关联的threadLocals也会被自动释放,在很大程度上避免了内存泄漏的问题
3. Netty中的进一步改进
Netty自定义了一个名为FastThreadLocal的东西
大概想法:
原版ThreadLocal中,在ThreadLocal.ThreadLocalMap中查找时,采用的是线性探测法,发生哈希碰撞时会导致查询变慢
为了避免这一问题,Netty为每个FastThreadLocal都设置了独一无二的编号,Thread可以直接根据这个编号寻址
这样做绝对不会有哈希碰撞,但是占用的空间也相应变大了,也就是空间换时间的套路。
4. ThreadLocal与内存泄漏
ThreadLocal有个很微妙的地方在于,它在某些场景下,还是会发生内存泄漏
如果我们在函数里定义了一个局部的ThreadLocal变量,主线程往里面set了一个很大的对象Huge后就退出这个函数该干嘛干嘛去了
现在这个ThreadLocal连带着Huge都是垃圾了,但是gc能回收他们吗?
按照一般的思路,ThreadLocal和Huge都会被Thread自带的threadLocals引用,所以都不会被回收。
但是JDK的作者比我机智很多了,他们把ThreadLocal.ThreadLocalMap.Entry弄成了弱引用(WeakReference),也就是说没有引用的ThreadLocal对象是会在full gc中被回收的。
但是问题依然存在:虽然ThreadLocal被回收了,但是它关联的Huge对象却还在,这可如何是好?
JDK的作者此时又玩了个骚操作,在对ThreadLocal做set操作时,会去检查ThreadLocal.ThreadLocalMap的底层数组,如果发现某个key是null了(ThreadLocal被gc了),它会把对应的value也设为null,这样Huge对象就可以被释放了。
但是为了性能考虑,这个检查操作不会遍历整个底层数组,而是每次只扫描一小段,所以在某些特定的场景下,还是会发生内存泄漏的。
ThreadLocal深度解析的更多相关文章
- ThreadLocal深度解析和应用示例
开篇明意 ThreadLocal是JDK包提供的线程本地变量,如果创建了ThreadLocal<T>变量,那么访问这个变量的每个线程都会有这个变量的一个副本,在实际多线程操作的时候,操作的 ...
- Java ThreadLocal深度解析
首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的.各 ...
- mybatis 3.x源码深度解析与最佳实践(最完整原创)
mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...
- Spring源码深度解析之事务
Spring源码深度解析之事务 目录 一.JDBC方式下的事务使用示例 (1)创建数据表结构 (2)创建对应数据表的PO (3)创建表和实体之间的映射 (4)创建数据操作接口 (5)创建数据操作接口实 ...
- [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析
[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...
- 第37课 深度解析QMap与QHash
1. QMap深度解析 (1)QMap是一个以升序键顺序存储键值对的数据结构 ①QMap原型为 class QMap<K, T>模板 ②QMap中的键值对根据Key进行了排序 ③QMap中 ...
- Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN
http://m.blog.csdn.net/blog/wu010555688/24487301 本文整理了网上几位大牛的博客,详细地讲解了CNN的基础结构与核心思想,欢迎交流. [1]Deep le ...
- (转载)(收藏)OceanBase深度解析
一.OceanBase不需要高可靠服务器和高端存储 OceanBase是关系型数据库,包含内核+OceanBase云平台(OCP).与传统关系型数据库相比,最大的不同点, 是OceanBase是分布式 ...
- Kafka深度解析
本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/2015/01/02/Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅 ...
随机推荐
- CSS3基础选择器
/*选择器分组:多个选择器使用同一个样式*/ h1,h2,a{ color: blue; } strong{ color: aquamarine; } /*选择器继承:body中未设置样式的会使用继承 ...
- 【题解】HAOI2011Problem b
第一次接触莫比乌斯反演,总之脑子都快要炸掉了……好难啊!本蒟蒻表示根本无法理解呜呜呜呜呜……不过在机房DL的帮助下总算是磕磕绊绊的A掉了这一题: 这道题目要我们的求的是:(1)ΣiΣj [gcd(i, ...
- [洛谷P1337][JSOI2004]平衡点 / 吊打XXX
题目大意:有$n$个重物,每个重物系在一条绳子上.所有绳子系在一起,问绳结最终平衡于何处. 题解:$NOIP$前学学模拟退火,但发现我脸好黑啊... 卡点:脸黑 C++ Code: #include ...
- 洛谷 P4168 [Violet]蒲公英 解题报告
P4168 [Violet]蒲公英 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多 ...
- 一些比较高效的CSS写法建议
当浏览器解析html的时候,它构造了一个文档树来展现所有被显示的元素. 它在特定的样式表中去匹配元素,根据标准的css的层叠,继承和顺序规则, 在mozilla的实现中(可能其他的也是这样),对于每一 ...
- Python爬虫学习笔记之爬取新浪微博
import requests from urllib.parse import urlencode from pyquery import PyQuery as pq from pymongo im ...
- Tomcat部署时war和war exploded区别及验证
war和war exploded的区别 在使用IDEA开发项目的时候,部署Tomcat的时候通常会出现下边的情况: 是选择war还是war exploded 这里首先看一下他们两个的区别: war模式 ...
- Eclipse Tomcat部署项目没有加载新加的静态资源文件
额,一直用MyEclipse,后来用Eclipse时,启动项目后去Tomcat webapps找对应文件夹,发现没有,才知道Eclipse 默认不往本地Tomcat部署. 1.eclipse不像MyE ...
- 【Foreign】猜测 [费用流]
猜测 Time Limit: 10 Sec Memory Limit: 256 MB Description Input Output Sample Input 3 1 1 1 2 2 1 Samp ...
- 下拉列表 JComboBox 的使用
下拉列表(JComboBox)通常显示一个可选条目,允许用户在一个下拉列表中选择不同条目,用户也可以在文本区内输入选择项. package first; import java.awt.FlowLay ...