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是一种分布式的,基于发布/订阅 ...
随机推荐
- 【UML】状态图介绍
1.Statechart Diagram 即状态图,主要用于描述一个对象在其生存期间的动态行为,表现为一个对象所经历的状态序列.引起状态转移的事件(Event).因状态转移而伴随的动作(Action) ...
- RPC里面的序列化反序列化以及拆包粘包
1.序列化(1)什么是序列化? Java的序列化是把对象转换成有序字节流的过程.以便进行网络传输或者保存到本地.(2)为什么要序列化? 当两个进程进行远程通信时,如果需要发送各种各样的数据,文本.音频 ...
- [C/C++] 深拷贝和浅拷贝
·默认拷贝构造函数可以完成对象的数据成员值简单地复制-----浅拷贝 ·对象的数据资源是由指针指示的堆时,默认拷贝构造函数仅作指针值的复制,需要显式定义拷贝构造函数-----深拷贝 首先定义几个点: ...
- 【bzoj4750】密码安全 单调栈
题目描述 模10^9+61 输入 第一行包含一个正整数 T ,表示有 T 组测试数据. 接下来依次给出每组测试数据.对于每组测试数据: 第一行包含一个正整数 n . 第二行包含 n 个非负整数,表示 ...
- NIO Q&A(持续补充。。。。)
Q:NIO是非阻塞的.但调用的selector.select()方法会阻塞.这和NIO非阻塞岂不是矛盾了? A:非阻塞指的是 IO 事件本身不阻塞,但是获取 IO 事件的 select 方法是需要阻塞 ...
- GET传值
发送页: <form id="form1" runat="server"> <div> <asp:TextBox ID=</ ...
- [BZOJ1921] [CTSC2010]珠宝商
Description Input 第一行包含两个整数 N,M,表示城市个数及特征项链的长度. 接下来的N-1 行, 每行两个整数 x,y, 表示城市 x 与城市 y 有直接道路相连.城市由1~N进行 ...
- BZOJ1143 [CTSC2008]祭祀river 【二分图匹配】
1143: [CTSC2008]祭祀river Time Limit: 10 Sec Memory Limit: 162 MB Submit: 3236 Solved: 1651 [Submit] ...
- 【CF Round 434 B. Which floor?】
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
- git clone 出错 fatal: pack has bad object at offset 26060927: inflate returned -3
$ git clone http://xxx.xxx.cn/liyafei/developer.gitCloning into 'developer'...remote: Counting objec ...