ThreadLocal 的原理

set方法需要首先获得当前线程对象Thread;

然后取出当前线程对象的成员变量ThreadLocalMap;

如果ThreadLocalMap存在,那么进行KEY/VALUE设置,KEY就是ThreadLocal;

如果ThreadLocalMap没有,那么创建一个;

说白了,当前线程中存在一个Map变量,KEY是ThreadLocal,VALUE是你设置的值。

get 其实揭示了ThreadLocalMap里面的数据存储结构,从代码来看,ThreadLocalMap中存放的就是Entry,Entry的KEY就是ThreadLocal,VALUE就是值

在JAVA里面,存在强引用、弱引用、软引用、虚引用。这里主要谈一下强引用和弱引用。

强引用,就不必说了,类似于:

A a = new A();

B b = new B();

考虑这样的情况:

C c = new C(b);

b = null;

考虑下GC的情况。要知道b被置为null,那么是否意味着一段时间后GC工作可以回收b所分配的内存空间呢?答案是否定的,因为即便b被置为null,但是c仍然持有对b的引用,而且还是强引用,所以GC不会回收b原先所分配的空间!既不能回收利用,又不能使用,这就造成了内存泄露。

那么如何处理呢?

可以c = null;也可以使用弱引用!(WeakReference w = new WeakReference(b);)

clipboard.png

ThreadLocal使用到了弱引用,是否意味着不会存在内存泄露呢?

首先来说,如果把ThreadLocal置为null,那么意味着Heap中的ThreadLocal实例不在有强引用指向,只有弱引用存在,因此GC是可以回收这部分空间的,也就是key是可以回收的。但是value却存在一条从Current Thread过来的强引用链。因此只有当Current Thread销毁时,value才能得到释放。

因此,只要这个线程对象被gc回收,就不会出现内存泄露,但在threadLocal设为null和线程结束这段时间内不会被回收的,就发生了我们认为的内存泄露。最要命的是线程对象不被回收的情况,比如使用线程池的时候,线程结束是不会销毁的,再次使用的,就可能出现内存泄露。

那么如何有效的避免呢?

事实上,在ThreadLocalMap中的set/getEntry方法中,会对key为null(也即是ThreadLocal为null)进行判断,如果为null的话,那么是会对value置为null的。我们也可以通过调用ThreadLocal的remove方法进行释放!

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    余生动听阅读 13,594评论 0 11
  • 彩排完,天已黑
    刘凯书法阅读 9,771评论 1 3
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 127,424评论 2 7

友情链接更多精彩内容