简介

  ThreadLocal在Java多线程开发中常见的一个类,在面试中也经见的问题,比如ThreadLocal的作用是什么,ThreadLocal的实现原理是什么等等。ThreadLocal是java中一个类,用于实现变量在多线程并发环境下维持线程的封闭性(封闭指的是可变对象对于其他线程是不可访问,不可操作的)。所以ThreadLocal其实可以当做一个线程内的局部变量来理解。

使用场景

当我们创建一个数据库连接,并且不希望在代码中互相传递,我们会将它设置成全局变量。然而数据库连接并不一定是线程安全的,我们希望每一个线程维持一个连接。

 private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
}; public static Connection getConnection() {
return connectionHolder.get();
}

  如上述代码,当不同的线程来调用getConnection方法的时候,获取到是不一样的Connection对象。hibernate的session管理也是通过ThreadLocal来实现的。

源码分析

  先来看一下ThreadLocal中最常用的几个方法。

     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();
} ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
} public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

  ThreadLocal的get方法和set方法算是最常用的方法了。第3行和第21中对ThreadLocal的操作都是通过一个ThreadLocalMap进行读写来完成get和set,ThreadLocalMap是一个散列表。从第5行和第23行看出,ThreadLocalMap的key是this,指代的是ThreadLocal本身,value则是线程对应的变量值。有一点要注意的是,ThreadlocalMap是在ThreadLocal内部定义的静态内部类,却是Thread类的属性。

  刚才说过ThreadlocalMap是一个散列表,但是它跟HashMap不一样。HashMap解决Hash冲突的方式是使用分离链表法,但是ThreadlocalMap是通过线性探测法来解决Hash冲突,这里就不对这方面进行细讲。

  

内存泄漏

  简介了ThreadLocal不顺便讲一讲ThreadLocal内存泄漏问题感觉很不专业,但是讲这个问题之前,可以先看一下上面图中,ThreadLocalMap的Entry使用的是一个弱引用(WeakReference),Java的引用分为强软弱虚四种,弱引用的特点是,当一个对象只被一个弱引用链接的时候,下次GC就会将刚对象回收。其他的引用细节这里不做赘述。

  内存泄漏原因:当一个ThreadLocal对象使用完毕被系统回收之后,因为Entry中的key为弱引用(这里并非整个entry),ThreadLocalMap中就有一个Entry中的Key会被设置为Null,此时value仍然保存和entry之间的强链接,导致value无法回收。假如线程一直不关闭,而ThreadLocalMap有大量的key被回收,就会存在一堆entry的key为null,value各不相同且无法回收的状况,所以ThreadLocal的get、set、remove中都会进行对key==null的entry进行清理。

  有人说内存泄漏是因为弱引用引起的,其实并不是,如果使用强引用,则会导致必须手动清除不需要使用的entry。使用上更加麻烦,并且更加容易出Bug。

  总的来说,当ThreadLocal变量已经不使用的时候,最好做一次remove()动作进行清理,这会是一个好习惯。

ThreadLocal简析的更多相关文章

  1. 一个错误使用单例模式的场景及ThreadLocal简析

    近来参与一个Java的web办公系统,碰到一个bug,开始猜测是线程池管理的问题,最后发现是单例模式的问题. 即,当同时发起两个事务请求时,当一个事务完成后,另一个事务会抛出session is cl ...

  2. 简析ThreadLocal原理及应用

    简析ThreadLocal原理及应用 原创: 东晨雨 JAVA万维猿圈 4月17日 ThreadLocal的源码加上注释不超过八百行,源码结构清晰,代码也比较简洁.ThreadLocal可以说是Jav ...

  3. JDK框架简析--java.lang包中的基础类库、基础数据类型

    题记 JDK.Java Development Kit. 我们必须先认识到,JDK不过,不过一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含 ...

  4. CGLib 简析

    背景 JDK 动态代理存在的一些问题: 调用效率低 JDK 通过反射实现动态代理调用,这意味着低下的调用效率: 每次调用 Method.invoke() 都会检查方法的可见性.校验参数是否匹配,过程涉 ...

  5. 简析.NET Core 以及与 .NET Framework的关系

    简析.NET Core 以及与 .NET Framework的关系 一 .NET 的 Framework 们 二 .NET Core的到来 1. Runtime 2. Unified BCL 3. W ...

  6. 简析 .NET Core 构成体系

    简析 .NET Core 构成体系 Roslyn 编译器 RyuJIT 编译器 CoreCLR & CoreRT CoreFX(.NET Core Libraries) .NET Core 代 ...

  7. RecycleView + CardView 控件简析

    今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...

  8. Java Android 注解(Annotation) 及几个常用开源项目注解原理简析

    不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...

  9. PHP的错误报错级别设置原理简析

    原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices inclu ...

随机推荐

  1. PAT_A1064#Complete Binary Search Tree

    Source: PAT A1064 Complete Binary Search Tree (30 分) Description: A Binary Search Tree (BST) is recu ...

  2. 引入css文件时,css link和@import区别

    这里link与@import介绍的是html引入css的语法单词.两者均是引入css到html的单词. 一.了解基本 1.link语法结构 <link href="CSSurl路径&q ...

  3. 字符编码到python编辑器流程

    字符(存储了信息的东西)编码(): 键盘发送的是电流-->主机(内存)接受到电流(当作010100110101)-->显示屏 接受电流(当作010100110101------->键 ...

  4. NFS服务器简易安装

    1.服务端 创建挂载目录 # mkdir /data/nfs 安装NFS软件 # yum install nfs-utils -y 添加配置信息 # vim /etc/exports /data/nf ...

  5. bias、variance与拟合之间的关系

    Error = Bias^2 + Variance+Noise 误差的原因: 1.Bias反映的是模型在样本上的输出与真实值之间的误差,即模型本身的精准度,即算法本身的拟合能力. 2.Variance ...

  6. gcc 4步编译过程

    一. gcc编译过程  1. 预处理: 主要进行宏替换以及头文件的展开  gcc  -E   *.c  -o  *.i 2.  编译::编译生成汇编文件,会检查语法错误   gcc  -S   *.i ...

  7. VBA中msgbox的用法小结

    1.作用在消息框中显示信息,并等待用户单击按钮,可返回单击的按钮值(比如“确定”或者“取消”).通常用作显示变量值的一种方式.2.语法MsgBox(Prompt[,Buttons][,Title][, ...

  8. C#让两个长度相同的数组一一对应

    比如: string a[]={"x","y","z"} "} 用字典使其一一对应 Dictionary<string, s ...

  9. PHP算法之两数之和

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元 ...

  10. 阿里云Aliplayer高级功能介绍(一):视频截图

    基本介绍 H5 Video是不提供截图的API的, 视频截图需要借助Canvas,通过Canvas提供的drawImage方法,把Video的当前画面渲染到画布上, 最终通过toDataURL方法可以 ...