ThreadLocal内存泄漏分析

ThreadLocal是什么?来,百度百科

ThreadLocal是Thread的局部变量,用于编多线程程序,对解决多线程程序的并发问题有一定的启示作用。

ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。

就是一个当前线程私有的保存一些当前线程内共享变量的一个东西。可以用来保存用户信息(我这样搞的,也不知道对不对)以及跨很多方法,在spring拦截器中通过解析JWT获得用户信息,然后调用service查找完整用户,最后保存到ThreadLocal中,在所有完成后再清除

好了,进入正题

先来段源码:

public class Thread implements Runnable {
 .......

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

    /*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
 .......


可以看到在Thread类里面有一个 ThreadLocal.ThreadLocalMap 类型的threadLocals一看是很多threadlocal嘛。这里贴上马士兵老师的图
【图不知道怎么传】
可以看到threadlocal的存储方式,将自己作为key,存储的值作为value放在map中,这里再来看一下源码

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;
    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

这里的super(k)的意思是调用父类的构造函数,而父类是啥呢,显而易见是WeakReference是弱引用,弱引用有个特点就是只要发生垃圾回收,它所指向的对象就会被回收。那为啥threadlocal没有被回收呢,其实还有个强引用指向他,这样就保证了不会被回收,那为啥不把key也设置成强引用,但是呢,图片上也说了,如过说将tl=null的话。这个对象会被回收吗,显然是不可能的,因为key也是强应用嘛,属于gc root,肯定不可能被回收。但是外部又访问不到,这不就造成内存泄漏了。所以说被设置为弱引用,但是这样就不会发生内存泄露了吗?

不是的,依然会发生,假设将tl=null,因为key是弱引用,所以只要发生垃圾回收就会被jvm回收,这样的话value的值怎么访问?k都没了还有v啥事,有人会说了,线程被回收了不就好了,是的。但是现在基本上都是使用线程池,线程还会被回收吗。所以说,依然会发生内存泄漏,所以在使用完threadlocal后要记得调用remove方法移除。

posted @ 2020-12-08 19:58  小鸡小鸡快点跑  阅读(159)  评论(0)    收藏  举报