并发编程之ThreadLocal

ThreadLocal基础知识

很多地方叫做线程本地变量,也有些地方叫做线程本地存储。

ThreadLocal为变量在每个线程中都创建了一个副本,每个线程可以访问自己内部的副本变量。

线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。

Synchronized 用于线程间的数据共享,而 ThreadLocal 则用于线程间的数据隔离。

原理

在Java中,每个线程都拥有一个ThreadLocalMap,在里面存放线程自己的私有对象。ThreadLocalMap里有个Entry对象,继承了WeakReference。Entry对象里有个键值对,其中key是ThreadLocal,value为私有对象。

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

在ThreadLocal的生命周期中,存在以下引用。实线代表强引用,虚线代表弱引用。

当线程没有结束,但是ThreadLocal对象由于是用的弱引用,GC时被回收了。这时就可能导致线程中存在ThreadLocalMap<null, Object>的键值对,造成内存泄露。(ThreadLocal被回收,ThreadLocal关联的线程共享变量(value)还存在,且有强引用正在引用,不会被GC)。

解决办法:

(1)使用完线程共享变量后,显式调用ThreadLocalMap.remove()方法清除线程共享变量;

(2)在ThreadLocal的get(),set(),remove()的时候都会清除线程ThreadLocalMap里所有key为null的value。但如果只创建了ThreadLocal却没有使用这些方法,还是会导致内存泄漏。

(3)ThreadLocal定义为private static,但是这样延长了ThreadLocal的生命周期,可能导致内存泄漏。

总结

1)实际通过ThreadLocal创建的副本是存储在每个线程自己的threadLocalMap中的;

2)为何threadLocals的类型ThreadLocalMap的键值为ThreadLocal对象,因为每个线程中可有多个threadLocal变量,可以用不同的ThreadLocal作为key,区分不同的value方便存取。

3)在进行get之前,必须先set,否则会报空指针异常;如果想在get之前不需要调用set就能正常访问的话,必须重写initialValue()方法。

应用场景

最常见的ThreadLocal使用场景:用来解决数据库连接、Session管理等。

在spring MVC中,常用ThreadLocal保存当前登陆用户信息,这样线程在任意地方都可以取到用户信息了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值