扫码关注微信公众号

回复“面试手册”,获取本站PDF版

回复“简历”,获取高质量简历模板

回复“加群”,加入程序员交流群

回复“电子书”,获取程序员类电子书

当前位置: Java > Java并发高频面试题 > 61.ThreadLocal原理和内存泄露?

要搞懂ThreadLocal的底层原理需要看下他的源码,太长了,有兴趣的同学可以自己看看相关资料,这里只是简单介绍下结构,因为Threadlocal内存泄露是个高频知识点,并且需要简单了解ThreadLocal结构。

ThreadLocal的原理可以概括为下图:

ThreadLocal
ThreadLocal

从上图可以看出每个线程都有一个ThreadLocalMapThreadLocalMap中保存着所有的ThreadLocal,而ThreadLocal本身只是一个引用本身并不保存值,值都是保存在ThreadLocalMap中的,其中ThreadLocalThreadLocalMap中的key。其中图中的虚线表示弱引用。

这里简单说下Java中的引用类型,Java的引用类型主要分为强引用、软引用、弱引用和虚引用。

  • 强引用:发生 gc 的时候不会被回收。
  • 软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。
  • 弱引用:有用但不是必须的对象,在下一次GC时会被回收。
  • 虚引用:无法通过虚引用获得对象,虚引用的用途是在 gc 时返回一个通知。

为什么ThreadLocal会发生内存泄漏呢?

因为ThreadLocal中的key是弱引用,而value是强引用。当ThreadLocal没有被强引用时,在进行垃圾回收时,key会被清理掉,而value不会被清理掉,这时如果不做任何处理,value将永远不会被回收,产生内存泄漏。

如何解决ThreadLocal的内存泄漏?

其实在ThreadLocal在设计的时候已经考虑到了这种情况,在调用set()get()remove()等方法时就会清理掉keynull的记录,所以在使用完ThreadLocal后最好手动调用remove()方法。

为什么要将key设计成ThreadLocal的弱引用?

如果ThreadLocalkey是强引用,同样会发生内存泄漏的。如果ThreadLocalkey是强引用,引用的ThreadLocal 的对象被回收了,但是ThreadLocalMap 还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,发生内存泄漏。

如果是弱引用的话,引用的ThreadLocal的对象被回收了,即使没有手动删除,ThreadLocal也会被回收。value也会在ThreadLocalMap调用 set()get()remove() 的时候会被清除。

所以两种方案比较下来,还是ThreadLoaclkey为弱引用好一些。


点击面试手册,获取本站面试手册PDF完整版