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是一种分布式的,基于发布/订阅 ...
随机推荐
- C语言100例01 PHP版(练习)
题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 代码: for ...
- [剑指Offer] 27.字符串的排列
[思路]从第一位开始,判断每一位字符的所有可能性,依此递归. class Solution { public: void PermutationHelp(vector<string> &a ...
- 设置select和option的文字居中的方法
给select设置text-align:center在火狐浏览器下ok,但是在chrome浏览器无效,然后option在两个浏览器下设置text-align:center都是无效的,解决方法,设置样式 ...
- 条件查询Criteria
public User getUserByNameCri(String name){ Session session = null; User user = null; try { session = ...
- [CF1077C]Good Array
题目大意:一个序列是好的当且仅当有一个数是其它所有数的和,问一个序列可以删掉哪个数变成好的序列.输出所有方案. 题解:发现等于其他数的和的那个数一定是其中最大的,只要排序一下(其实只要找到最大的两个数 ...
- [Leetcode] spiral matrix ii 螺旋矩阵
Given an integer n, generate a square matrix filled with elements from 1 to n 2 in spiral order. For ...
- maven pom继承与聚合
一.POM聚合模块: 在分布式架构,分模块化开发中,每个某块可能都是一个单独的maven项目,能够独立的进行项目构架,当模块比较多时,可以使用maven聚合聚合项目来简化maven构建,一次构建多个项 ...
- 安卓和html的互相调用
1.写html和安卓布局 <Button android:id="@+id/btn" android:layout_width="wrap_content" ...
- 利用WebStorm来管理你的Github
什么是Github Github是一个共享虚拟主机服务,用于存放使用Git版本控制的软件代码和内容项目,以最简单的方式来说,其实就是一个代码库,上面有全世界无数优秀的码农上传自己的作品和大家共享(当然 ...
- QT QLayout 清空
QLayout* pLayout = (QLayout*)ui->frame->layout(); )) { QWidget* pWidget = child->widget(); ...