简介

  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. java执行顺序之深入理解clinit和init

    原文地址:https://blog.csdn.net/qq_36522306/article/details/80582758 前言: 最近研究了深入理解JVM这本书中的知识,对java中各部分执行的 ...

  2. MongoDB点滴

    0 http://blog.csdn.net/mydeman/article/details/6652387 1 MongoDB 内置连接池,不需要使用额外的连接池驱动 Note: The Mongo ...

  3. Flink 1.9 FlinkKafkaProducer 使用 EXACTLY_ONCE 错误记录

    使用flink FlinkKafkaProducer 往kafka写入数据的时候要求使用EXACTLY_ONCE语义 本以为本以为按照官网写一个就完事,但是却报错了 代码 package com.me ...

  4. 剑指offer——36二叉树和为某一值的路径

    题目描述 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.(注意: 在返回值的list中,数组长度大 ...

  5. Ctrl快捷键

    Ctrl + a - Jump to the start of the lineCtrl + b - Move back a charCtrl + c - Terminate the command ...

  6. 采用多个数据源是Spring的配置

    XML配置多多源文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="h ...

  7. java 传入多个参数时报"Parameter 'XXX' not found. Available parameters are [arg1, arg0, param1,..." 解决方案

    @Select("SELECT id FROM ae_post ORDER BY id DESC LIMIT #{page},#{size}") List<Post> ...

  8. SpringIOC中的注解配置

    Spring中的注解是个好东西,可以简化我们的操作,但是使用了注解又会在一定的程度上增加程序的耦合度,xml中的配置写在了类中虽然简化了开发过程,但是或多或少的违背了开闭原则.所以在开发过程中要先明确 ...

  9. JS事件 加载事件(onload)注意:1. 加载页面时,触发onload事件,事件写在<body>标签内。 2. 此节的加载页面,可理解为打开一个新页面时。

    加载事件(onload) 事件会在页面加载完成后,立即发生,同时执行被调用的程序. 注意:1. 加载页面时,触发onload事件,事件写在<body>标签内. 2. 此节的加载页面,可理解 ...

  10. 检测到“RuntimeLibrary”的不匹配项