本文基于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深度解析的更多相关文章

  1. ThreadLocal深度解析和应用示例

    开篇明意 ThreadLocal是JDK包提供的线程本地变量,如果创建了ThreadLocal<T>变量,那么访问这个变量的每个线程都会有这个变量的一个副本,在实际多线程操作的时候,操作的 ...

  2. Java ThreadLocal深度解析

    首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的.各 ...

  3. mybatis 3.x源码深度解析与最佳实践(最完整原创)

    mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...

  4. Spring源码深度解析之事务

    Spring源码深度解析之事务 目录 一.JDBC方式下的事务使用示例 (1)创建数据表结构 (2)创建对应数据表的PO (3)创建表和实体之间的映射 (4)创建数据操作接口 (5)创建数据操作接口实 ...

  5. [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析

    [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...

  6. 第37课 深度解析QMap与QHash

    1. QMap深度解析 (1)QMap是一个以升序键顺序存储键值对的数据结构 ①QMap原型为 class QMap<K, T>模板 ②QMap中的键值对根据Key进行了排序 ③QMap中 ...

  7. Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN

    http://m.blog.csdn.net/blog/wu010555688/24487301 本文整理了网上几位大牛的博客,详细地讲解了CNN的基础结构与核心思想,欢迎交流. [1]Deep le ...

  8. (转载)(收藏)OceanBase深度解析

    一.OceanBase不需要高可靠服务器和高端存储 OceanBase是关系型数据库,包含内核+OceanBase云平台(OCP).与传统关系型数据库相比,最大的不同点, 是OceanBase是分布式 ...

  9. Kafka深度解析

    本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/2015/01/02/Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅 ...

随机推荐

  1. CSS3基础选择器

    /*选择器分组:多个选择器使用同一个样式*/ h1,h2,a{ color: blue; } strong{ color: aquamarine; } /*选择器继承:body中未设置样式的会使用继承 ...

  2. 【题解】HAOI2011Problem b

    第一次接触莫比乌斯反演,总之脑子都快要炸掉了……好难啊!本蒟蒻表示根本无法理解呜呜呜呜呜……不过在机房DL的帮助下总算是磕磕绊绊的A掉了这一题: 这道题目要我们的求的是:(1)ΣiΣj [gcd(i, ...

  3. [洛谷P1337][JSOI2004]平衡点 / 吊打XXX

    题目大意:有$n$个重物,每个重物系在一条绳子上.所有绳子系在一起,问绳结最终平衡于何处. 题解:$NOIP$前学学模拟退火,但发现我脸好黑啊... 卡点:脸黑 C++ Code: #include ...

  4. 洛谷 P4168 [Violet]蒲公英 解题报告

    P4168 [Violet]蒲公英 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多 ...

  5. 一些比较高效的CSS写法建议

    当浏览器解析html的时候,它构造了一个文档树来展现所有被显示的元素. 它在特定的样式表中去匹配元素,根据标准的css的层叠,继承和顺序规则, 在mozilla的实现中(可能其他的也是这样),对于每一 ...

  6. Python爬虫学习笔记之爬取新浪微博

    import requests from urllib.parse import urlencode from pyquery import PyQuery as pq from pymongo im ...

  7. Tomcat部署时war和war exploded区别及验证

    war和war exploded的区别 在使用IDEA开发项目的时候,部署Tomcat的时候通常会出现下边的情况: 是选择war还是war exploded 这里首先看一下他们两个的区别: war模式 ...

  8. Eclipse Tomcat部署项目没有加载新加的静态资源文件

    额,一直用MyEclipse,后来用Eclipse时,启动项目后去Tomcat webapps找对应文件夹,发现没有,才知道Eclipse 默认不往本地Tomcat部署. 1.eclipse不像MyE ...

  9. 【Foreign】猜测 [费用流]

    猜测 Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output Sample Input 3 1 1 1 2 2 1 Samp ...

  10. 下拉列表 JComboBox 的使用

    下拉列表(JComboBox)通常显示一个可选条目,允许用户在一个下拉列表中选择不同条目,用户也可以在文本区内输入选择项. package first; import java.awt.FlowLay ...