ThreadLocal介绍

本文详细分析了ThreadLocal的工作原理,包括set、get和remove方法,强调了ThreadLocalMap的作用以及如何避免内存泄漏,尤其是在多线程环境下的内存管理问题。
摘要由CSDN通过智能技术生成

ThreadLocal

ThreadLocal提供了线程局部变量,每个线程都可以通过set和get方法来对这个变量进行操作,但不会和其他线程的局部变量冲突,实现了线程的数据隔离

源码分析:

set方法

public void set(T value) {
    Thread t = Thread.currentThread();
    //getMap就是为了获取当前线程的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    if (map != null)
        //如果map存在就直接以这个ThreadLocal为键,设置键和值
        map.set(this, value);
    else
        //否则就为他创建一个ThreadLocalMap,并设置第一个键和值
        createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

get方法

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        //如果当前线程的ThreadLocalMap存在,就尝试获取对应键值对
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    //如果threadLocals不存在或者当前的ThreadLocal不存在于这个map中
    return setInitialValue();
}
private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        //当前ThreadLocal不存在于map中,就加上,设置value为空
        map.set(this, value);
    else
        //如果map不存在就创建,并设置键值
        createMap(t, value);
    return value;
}
protected T initialValue() {
    return null;
}

remove方法

public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        m.remove(this);
}
private void remove(ThreadLocal<?> key) {
    Entry[] tab = table;
    int len = tab.length;
    int i = key.threadLocalHashCode & (len-1);
    for (Entry e = tab[i];
         e != null;
         e = tab[i = nextIndex(i, len)]) {
        if (e.get() == key) {
            //弱引用中的清除方法
            e.clear();
            //将key为null的键值对清除掉,get和set方法底层也有用到
            expungeStaleEntry(i);
            return;
        }
    }
}
private static int nextIndex(int i, int len) {
    return ((i + 1 < len) ? i + 1 : 0);
}

总结:

可以看出,ThreadLocal中并不存储值,只是作为一个key来让线程从ThreadLocalMap中获取value,从而实现了线程之间的数据隔离

  • 每个线程都维护着一个ThreadLocalMap,ThreadLocalMap是ThreadLocal的内部类
  • ThreadLocal中的set,实际上是向当前线程的ThreadLocalMap中设置值,键为创建的ThreadLocal对象

ThreadLocal内存泄漏问题

内存泄漏:程序中间动态分配了内存,但在程序结束时没有释放这部分内存,从而造成那部分内存不可用的情况

内存溢出:要求分配的内存超过了系统能给的

ThreadLocal中作为map中的key使用,而且ThreadLocalMap中的key是弱引用,弱引用对象在gc时会被回收,而ThreadLocalMap和Thread的生命周期一样长,就会存在key为null的情况,value访问不到,从而引发内存泄漏。所以,使用ThreadLocal时最后最好调用remove方法显式调用expungeStaleEntry方法手动删除key为null的value,防止value的积累

ThreadLocal的get和set方法某些时候也会调用expungeStaleEntry方法,但这是不及时的,而且不一定每次都会执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值