ThreadLocal源码解析和内存泄漏问题

jdk版本:1.8

第一次写博客,原因是为了公司的技术分享,写ThreadLocal相关的文章的原因是公司用的代码检测工具标记ThreadLocal对象存在内存泄露问题,加上之前对这个东东并不熟悉,于是看了一下源码找了一下资料,决定写一篇相关的博客作为分享。

* <p>Each thread holds an implicit reference to its copy of a thread-local
* variable as long as the thread is alive and the {@code ThreadLocal}
* instance is accessible; after a thread goes away, all of its copies of
* thread-local instances are subject to garbage collection (unless other
* references to these copies exist).

这是ThreadLocal类的注释,可以看出ThreadLocal类是一个给多个线程使用并提供独立的数据的一个工具。

//ThreadLocal.Class
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
}

//ThreadLocal.Class
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
}

从上边两段代码可以看出,实际上存储数据的是一个叫做ThreadLocalMap的类,而这个类会赋值给当前线程的threadLocals这个属性,也就是说不同的线程即使持有同一个ThreadLocal对象,在使用set方法的时候,都会生成各自的ThreadLoaclMap,保证了数据互不影响。

而内存泄漏是怎么一回事呢?

 /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

ThreadLocalMap的内部类Entry的key是ThreadLoacl对象的弱引用,弱引用在每次gc的时候都会被回收,但是只是key而已,Entry对象并不是弱引用,根据jvm的可达性分析算法,我们从上文可以看出来,当一个线程没有结束之前并且threadLocals属性是已经赋值ThreadLocalMap的时候,ThreadLocalMap对象则一直不会被回收,即使ThreadLoacl对象已经消亡。所以就会存在内存泄漏的问题。所以每一个线程使用ThreadLocal中的数据后要记得调用remove方法将引用断开,保证正确的gc不造成内存泄漏的可能。

我们的项目是在aop中声明了一个静态的ThreadLocal<Long>对象,切点进入之前会set一个时间戳进去,结束的时候拿出这个时间戳和当前时间做一个时间差的计算,了解到这个内存泄漏的风险之后,在切点结束之后会调用remove方法。

强引用,软引用,弱引用这些,可达性分析算法这些自行百度。。。ThreadLocalMap中的数据结构等源码和remove源码等以后可能会更新,建议读者先自行观看,拜拜。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值