简介

  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. Intellij IDEA 撸码最头大的问题。。

    想栈长我当初从 Eclipse 转用 IDEA 真是纠结,放弃然后尝试了N次,不过现在已经算是转型成功了,可以完全脱离 Eclipse 撸码了,虽然说我现在真的撸得非常少了.. 说到 IDEA 的痛点 ...

  2. Error creating bean with name 'unMblTotController': 注入失败

    今天新来的小伙子,进公司做项目,然后自己新建了包,出了以下错误 y.UnsatisfiedDependencyException: Error creating bean with name 'unM ...

  3. WinCE下的第二个窗口程序

    MFC写的,有些简陋,但是还是感觉不错,一个小小的计算器,各个方面的功能都完成了 但是唯独那个CEdit里面的文字不能右对齐.那个扩展风格用不了

  4. Balking Pattern不需要就不用做

    word自动保存功能,如果文档被修改了,后台线程每隔一段时间会自动执行保存功能,但是如果用户在自动保存之前用Ctrl+S手动保存呢?自动保存还会执行吗?答案是不会,因为这个操作时不需要重复做的. pu ...

  5. 简单的GridView分业,后台不需要写

    1前台代码: <asp:GridView ID="GridView1" runat="server" AllowPaging="True&quo ...

  6. latex 引用文献 bib

    study from : https://jingyan.baidu.com/article/925f8cb8bce1f0c0dce0564f.html 寻找文献 谷歌学术 from: https:/ ...

  7. (转)iframe 高度100%时,出现垂直滚动条

    问题 需求是这样的,iframe在一个div中,并且iframe高度与div一样,所以设置了iframe高度是100%,结果div出现了滚动条,在排除了padding.margin的因素外,还是有滚动 ...

  8. "一个实用的却被忽略的命名空间:Microsoft.VisualBasic":

        当你看到这个命名空间的时候,别因为是vb的东西就匆忙关掉网页,那将会是您的损失,此命名空间中的资源最初目的是为了简化vb.net开发而创建的,所以microsoft.visualbasic并不 ...

  9. Http学习(二)

    使用首部字段是为了给浏览器和服务器提供报文主体大小.所使用语言.认证信息等 4种首部字段类型 通用首部字段 请求首部字段 响应首部字段 实体首部字段 详细说明: HTTP首部字段类型 通用首部字段: ...

  10. VS2010-MFC(文档、视图和框架:分割窗口)

    转自:http://www.jizhuomi.com/software/226.html 上一节讲了文档.视图和框架结构中各对象之间的关系,本节主要讲讲在MFC中如何分割窗口. 分割窗口概述      ...