面试题——ThreadLocal相关

1、ThreadLocal是什么?

ThreadLocal是什么

ThreadLocal,即线程本地。如果创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地拷贝,多个线程操作这个变量的时候,实际是操作自己本地内存里面的变量,从而起到线程隔离的作用,避免了线程安全问题。

//创建一个ThreadLocal变量
private static ThreadLocal<String> localVariable = new ThreadLocal<>();

ThreadLocal的应用场景

最常见的ThreadLocal应用场景包括数据库连接管理,Session会话管理等。

每个线程都可以拥有独立的数据库连接,避免多线程环境下共享连接时会出现的并发问题。并发问题包括:

  • 一个线程在另一个线程完成数据库操作之前关闭了连接;
  • 一个线程的事务受到其他线程的操作影响。
    • 比如一个线程进行了更新数据的操作,还没有提交事务,然后另一个线程进行读操作,读取到未提交的更新数据,发生了类似于针对多个事务(一个连接一个事务)的脏读问题。
    • 再比如探索多线程使用同一个数据库connection的后果 - swave - 博客园 (cnblogs.com)中的例子,即:第一个线程插入了数据a,在执行conn.rollback()方法回滚事务之前,另一个线程插入数据b,然后执行了conn.commit方法提交了事务,将第一个线程插入的数据a一并提交到数据库中,导致第一个线程中不该提交的数据a被提交到数据库中,影响到了第一个线程的事务。

每个线程都可以独立管理自己的会话,避免影响其他线程的会话。

ThreadLocal的实现原理

  • Thread类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals,即每个线程都有一个属于自己的ThreadLocalMap;

  • ThreadLocalMap内部维护着Entry数组,每个Entry代表一个完整的对象,key是ThreadLocal本身,value是往ThreadLocal里设置的泛型值;

  • 每个线程在往ThreadLocal里设置值的时候,都会往自己的ThreadLocalMap里以键值对的形式存ThreadLocal的引用和在ThreadLocal里设置的值,读也是以某个ThreadLocal引用作为key,在自己的map里找对应的value,从而实现了线程隔离

ThreadLocal内存结构图:

在这里插入图片描述

由结构图可以看出:

  • Thread对象中持有⼀个ThreadLocal.ThreadLocalMap的成员变量;
  • ThreadLocalMap内部维护了Entry数组,每个Entry代表⼀个完整的对象,key是ThreadLocal本身,value是往ThreadLocal里设置的泛型值。

2、知道ThreadLocal 内存泄露问题吗?

先看一下ThreadLocal的引用示意图

在这里插入图片描述

ThreadLocalMap中使用的 key 为 ThreadLocal 的弱引用,如下:

在这里插入图片描述

弱引用:只要垃圾回收机制一运行,不管JVM的内存空间是否充足,都会回收该对象占用的内存。

因此,如果ThreadLocal不再被引用(同一个ThreadLocal对象可以有多个引用,其中一个引用是Entry对象中的弱引用key,而这里的引用指的是来自其他变量对该对象的强引用(比如上面引用示意图中的ThreadLocal Ref),没有了这个引用,只有弱引用的ThreadLocal对象就会被JVM垃圾回收),当JVM GC时就会被垃圾回收器回收(ThreadLocalMap的Key变为null),但是因ThreadLocalMap生命周期和Thread是一样的,它这时候如果不被回收,就会出现这种情况:ThreadLocalMap的key为null,value还在,这就会造成了内存泄漏问题

为了解决threadLocal潜在的内存泄漏的问题,ThreadLocal在set、get、remove方法(这些方法最终调用ThreadLocalMap的getEntry,set,remove方法,这些方法中有针对entry元素的处理)中都有相应的处理。若发现ThreadLocalMap某entry key为null,则将entry value和其entry本身都设置为null,下一次GC的时候就会被回收掉。

参考

  1. 探索多线程使用同一个数据库connection的后果 - swave - 博客园 (cnblogs.com)
  2. ThreadLocal 详解 | JavaGuide(Java面试 + 学习指南)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值