并发编程笔记—ThreadLocal

1、是什么?

 线程类中声明了一个ThreadLocal.ThreadLocalMap类型的成员变量,是为了维护线程本地变量而设计的。

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ...
}

 ThreadLocal,即线程局部变量,提供了线程本地实例。同一个ThreadLocal 所包含的对象,在不同的Thread中有不同的副本,即不同线程之间是隔离的,不存在多线程间的共享问题。

ThreadLocal是一个泛型类,保证可以接受任何类型的对象。ThreadLocalMap是对应的一个静态内部类,以ThreadLocal对象为键、任意对象为值的存储结构。

public class ThreadLocal<T> {  
        
    static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

        private static final int INITIAL_CAPACITY = 16;

        private Entry[] table;

        private int size = 0;
        ....
    }

}        

使用set()、get()方法可以操作对应当前线程ThreadLocal对应的Value

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            // 将当前ThreadLocal作为key
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }
    
    // 获取当前线程的threadLocals变量
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

2、内存泄漏问题

ThreadLocalMap的Entry类中key为ThreadLocal的弱引用,特点就是,如果这个对象只存在弱引用,那么在下一次垃圾回收的时候必然会被清理掉。

java对象的引用包括 : 强引用,软引用,弱引用,虚引用 。

  • 强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它,当内存空间不足时,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用对象来解决内存不足的问题。

  • 如果一个对象只具有软引用,则内存空间充足时,垃圾回收器不会回收它;如果内存空间不足了,就会回收这些对象的内存。

  • 线程扫描内存区域时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定很快发现那些只具有弱引用的对象。

  • 虚引用顾名思义,就是形同虚设。与其他几种引用都不同,虚引用不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

所以如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候会被清理掉的,这样 ThreadLocalMap中使用这个 ThreadLocal 的 key也会被清理掉。但是value 是强引用,不会被清理,就会出现 key 为 null 的 value,当value是很大的对象就会存在内存泄漏风险。

ThreadLocalMap实现中已经考虑了这种情况,在调用 set()、get()、remove() 方法的时候,会清理掉 key 为 null 的记录。如果说会出现内存泄漏,那只有在出现了 key 为 null 的记录后,没有手动调用 remove() 方法,并且之后也不再调用 get()、set()、remove() 方法的情况下。

那为什么还要设计成弱引用?

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值