ThreadLocal

前言

  在阿里Java开发手册1.7第6点中提到:必须回收自定义的ThreadLocal变量,尤其在线程池场景下,线程经常被反复用,如果不清理自定义的ThreadLocal变量,则可能会影响后续业务逻辑和造成内存泄漏等问题。尽量在代码中使用try-finally块回收。因此做了对ThreadLocal进行了学习。

一、是什么?

 

 

 简单翻译过来是:

此类提供线程局部变量。
这些变量不同于它们的正常对应变量,因为每个访问一个(通过它的 get 或 set 方法)的线程都有它自己的、独立初始化的变量副本
ThreadLocal 实例通常是希望将状态与线程相关联的类中的私有静态字段(例如,用户 ID 或事务 ID)。

 

 

 同样也提到:线程消失后,会进行垃圾回收;是否可以理解为:那如果使用线程池,线程被反复使用是否可以理解为不主动删除,将会造成内存泄漏问题。

只要线程处于活动状态并且 ThreadLocal 实例可访问,每个线程都持有对其线程局部变量副本的隐式引用;
在线程消失后,它的所有线程本地实例副本都将受到垃圾回收(除非存在对这些副本的其他引用)。

二、能干嘛?

  实现每一个线程都有自己专属的本地变量副本(自己用自己的变量不麻烦别人,不和其他人共享,人人有份,人各一份),
主要解决了让每个线程绑定自己的值,通过使用get()和set()方法,获取默认值或将其值更改为当前线程所存的副本的值从而避免了线程安全问题

三、Thread、ThreadLocal和ThreadLocalMap三者之间的关系

 

  hreadLocalMap从字面上就可以看出这是一个保存ThreadLocal对象的map(其实是以ThreadLocal为Key),不过是经过了两层包装的ThreadLocal对象

 

 

  JVM内部维护了一个线程版的Map<Thread,T>(通过ThreadLocal对象的set方法,结果把ThreadLocal对象自己当做key,放进了ThreadLoalMap中),每个线程要用到这个T的时候,用当前的线程去Map里面获取,通过这样让每个线程都拥有了自己独立的变量,人手一份,竞争条件被彻底消除,在并发模式下是绝对安全的变量。

三、内存泄漏问题

  ThreadLocalMap中Entry的key引用是弱引用;

  为什么使用弱引用?

    若这个key引用是强引用,就会导致key指向的ThreadLocal对象及v指向的对象不能被gc回收,造成内存泄漏;
    若这个key引用是弱引用就大概率会减少内存泄漏的问题(还会出现key为null的雷)。使用弱引用,就可以使ThreadLocal对象在方法执行完毕后顺利被回收且Entry的key引用指向为null。

 

   为什么key为null也会造成内存泄漏?

  ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal没有外部强引用引用他,那么系统gc的时候,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,如果当前线程再迟迟不结束的话(比如正好用在线程池),这些key为null的Entry的value就会一直存在一条强引用链,使得key为null的Entry不能够回收

 

 

这也是为什么手册上强调使用完后需要调用remove();

其实get(),set(),remove()方法都会清除key为null的Entry;

posted @   金玉良猿  阅读(92)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!
点击右上角即可分享
微信分享提示