一文详解ThreadLocal 使用场景,源码分析,内存泄漏分析

ThreadLocal

使用场景:

场景1. ThreadLocal用作保存每个线程独享的对象,为每个线程都创建一个副本,修改时只是对自己副本的操作,确保线程安全。典型的需要使用的类就是 SimpleDateFormat。

场景2.ThreadLocal每个线程需要独立保存信息,以便提供其他方法更方便的获取。避免了参数的传递,类似与全局变量的概念。

Thread、ThreadLocal、ThreadLocalMap之间关系

我们先从ThreadLocal#set方法开始:

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

首先我们可以发现根据这行代码 **map.set(this, value);**可以得出结论是ThreadLocalMap存放的Key是ThreadLocal,value是我们存放的值。

ThreadLocalMap的Entry table:

Keyvalue
ThreadLocalvalue
ThreadLocalvalue
ThreadLocalvalue

那么ThreadLocal是如何创建的呢:

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

Thread存在一个变量threadLocals

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

所以在ThreadLocal的set方法中如果第一次ThreadLocalMap不存在会创建ThreadLocalMap并且赋值给当前线程的Thread类的threadLocals变量。

综上所述:
所以每个线程都有与之对应的ThreadLocalMap,在ThreadLocal第一次使用set的时候被创建出来。每个ThreadLocalMap中存放了一个Entry的数组,其中Entry对象的Key为ThreadLocal ,value为所保存的值。

ThreadLocal内存泄漏分析

什么是内存泄漏

当一个对象不再被使用但是却无法回收其占用的内存,我们称之为内存泄漏。在这里插入图片描述

根据上面的分析我们画出了ThreadLocal的内存引用图。关于 Java中的四种引用类型

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

这里的Entry为啥是弱引用(WeakReference)

如果不是弱引用当ThreadLocal为null 的时候依然存在一条引用:
Thread -> ThreadLocalMap -> Entry key -> ThreadLocal,这时候Key依然是无法被垃圾回收所回收掉的。当这个引用为弱引用ThreadLocal的内存就会被垃圾回收回收掉,所以Key才要设计成弱引用。

value泄漏:
虽然上面的解决了Key Threadlocal的泄漏问题,但是Entry中的存在(null,value)这种的数据,ThreadLocal 每次set.get的时候都会删除这样的entry对象。JDK同样也考虑到了这个问题,在执行ThreadLocal的set、remove、rehash等方法时,它都会扫描key为null的Entry,如果发现某个Entry的key为null,这样value就可以被回收了。

但是假设threadLocal已经不使用了 但是线程一直存活,这些方法没有被调用,那还是会泄漏。

如何避免:
调用 ThreadLocal 的 remove 方法

拉勾教育版权所有:https://kaiwu.lagou.com/course/courseInfo.htm?courseId=16调用 ThreadLocal 的 remove 方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值