ThreadLocal原理

1 public void set(T value) {
2     // 获取当前线程
3     Thread t = Thread.currentThread();
4     // 获取当前线程的ThreadLocalMap
5     ThreadLocalMap map = getMap(t);
6     //以this为key, 获取 value
7     map.set(this, value);
8 }
1 ThreadLocalMap getMap(Thread t) {
2    return t.threadLocals;
3 }

ThreadLocal核心代码如上。通过当前线程 currentThread 中的 threadLocals(本质是一个Map),以当前的ThreadLocal对象即this为健, value为值来维系value与currentThread的对应关系。

 

ThreadLocal中的弱引用与内存泄漏问题:

ThreadLocal自身并不储存值,而是作为一个key来让线程从ThreadLocal获取value。Entry是中的key是弱引用,所以jvm在垃圾回收时如果外部没有强引用来引用它,ThreadLocal必然会被回收。但是,作为ThreadLocalMap的key,ThreadLocal被回收后,ThreadLocalMap就会存在null,但value不为null的Entry。若当前线程一直不结束,可能是作为线程池中的一员,线程结束后不被销毁,或者分配(当前线程又创建了ThreadLocal对象)使用了又不再调用get/set方法,就可能引发内存泄漏。其次,就算线程结束了,操作系统在回收线程或进程的时候不是一定杀死线程或进程的,在繁忙的时候,只会清除线程或进程数据的操作,重复使用线程或进程(线程id可能不变导致内存泄漏)。因此,key弱引用并不是导致内存泄漏的原因,而是因为ThreadLocalMap的生命周期与当前线程一样长,并且没有手动删除对应value。

那么,为什么要将Entry中的key设为弱引用?相反,设置为弱引用的key能预防大多数内存泄漏的情况。如果key 使用强引用,引用的ThreadLocal的对象被回收了,但是ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。如果key为弱引用,引用的ThreadLocal的对象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被GC回收。value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。

如何避免上述弱引用引发的内存泄漏?

在使用完ThreadLocal时,及时调用它的的remove方法清除数据。

 参考:https://zhuanlan.zhihu.com/p/58636499

    https://www.zhihu.com/question/37401125

posted @   三板斧-Howie  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示