ThreadLocal

ThreadLocal可以保存一个对象,在多线程环境下,每个线程可以创建自己对象,对自己所获取的对象进行操作,而不会影响其他线程。ThreadLocal并不是让多个线程安全的使用同一个对象,而是让每个线程拥有自己的对象。

在ThreadLocal中主要有get()获取当前线程对象,set(T value)设置当前线程对象,initialValue()初始化当前线程对象。ThreadLocal初始化时可以重写intialValue进行初始化,否则默认变量副本为null。

private static ThreadLocal<Obejct> local = new ThreadLocal<Object>() {
   @Override
   Object initialValue() {
      reture new Object();
   }
};

看到这里你可能会说,那我直接为每一个线程创建一个object对象不就行了,干嘛用ThreadLocal呀?这是因为这个对象可能会在线程执行过程中多处被使用,我们不想每次都创建它,或者将它作为一个参数传来传去的,使用ThreadLocal之后,就可以方便的使用threadLocal.get()的方式进行获取。

ThreadLocal的原理是在每一个thread中都有一个ThreadLocalMap对象。当调用ThreadLocal的get方法时,会先获取当前线程的ThreadLocalMap对象,以当前ThreadLocal对象实例为Key获取存储在map中当前线程的value,如果map为空,则根据initialValue值,初始化ThreadLocalMap将key,value放进去。

set也是如此,先获取当前线程的ThreadLocalMap对象,map如果存在,则将key对应的新值存入,map不存在则创建map,存入key,value

ThreadLocalMap底层是以数组的形式来存储的Entry

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

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

内存泄漏

threadLocal中的对象是存储在当前Thread的ThreadLocalMap中,ThreadLocalMap的底层数据结构是数组,存储的元素是Entry,它继承了WeakReference,Entry构造方法中需要传入ThreadLocal对象引用和vaule,在Entry中threadLocal是一个弱引用,如果强引用threadLocal = new ThreadLocal()被置为null,即threadLocal=null,那么进行一次GC后原来threadLocal引用指向的对象会被回收掉,这样使用了该对象的entry中的ThreadLocal也变成了null,它所对应的ThreadLocalMap中的entry也不能被获取到了,就有可能出现内存泄漏;

//ThreadLocalMap中的获取Entry的方法,因为对应的ThreadLocal对象已被回收,所以对应entry再也不能被获取到
private Entry getEntry(ThreadLocal<?> key) {
    int i = key.threadLocalHashCode & (table.length - 1);
    Entry e = table[i];
    if (e != null && e.get() == key)
        return e;
    else
        return getEntryAfterMiss(key, i, e);
}

但是即使Entry中的threadLocal为指向threadLocal对象的强引用,当threadLocal被置为null后,不光ThreadLocalMap中的entry连threadLocal原本指向的对象都不会被回收掉了,但是外部已经没有任何指向原ThreadLocal对象的引用了,内存泄露可能会更严重。

出现这种情况的原因是threadLocalMap它的生命周期与当前thread相同,当线程存活,threadLocalMap就不会被回收,只要不显式的调用threadLocal.remove方法,threadLocalMap中的entry永远都存在,因此将key使用弱引用,是ThreadLocal应对有可能发生的内存泄露自己所作的优化。

当我们使用ThreadLocal的get set remove方法时都会在本Thread的ThreadLocalMap中删除一些key为null的节点,这也是ThreadLocal为了避免内存泄漏所作的努力。但最好的方式是,当我们不再使用一个threadLocal中存储的对象时,主动调用它的remove()方法,减少threadLocal内存泄漏的可能性

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值