ThreadLocal

1. ThreadLocal概念

ThreadLocal:线程变量,ThreadLocal中填充的变量属于当前线程。用于线程间的数据隔离。

每个Thread有一个ThreadLocalMap

在这个Thread里定义若干个ThreadLocal对象,用来保存线程数据。每个ThreadLocal对象使用set方法创建一个Entry :<ThreadLocal,Value>

这些Entry都保存到了这个线程持有的ThreadLocalMap

如图:

2. ThreadLocal内存泄露

Java中的引用类型:

引用:指向内存地址

1.强引用(StrongReference)

使用 new 关键字创建的对象,不会被回收。程序代码中普遍存在的引用赋值。

当内存空间不足,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。

2.软引用(SoftReference)

在内存不足时会被回收,适用于 缓存。

3.弱引用(WeakReference)

不论内存是否足够,只要发生 GC,弱引用的对象都会被回收。

4.虚引用(PhantomReference)

虚引用并不会决定对象的生命周期,如同没有引用一般,虚引用主要用来跟踪对象被垃圾回收的活动

程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速 JVM 对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生

内存泄露原因

Entry<ThreadLocal(key), Value>中

        Key弱引用->ThreadLocal对象

        Value强引用->要保存的线程局部变量。

线程经常使用池化思想也就是线程池管理(避免了频繁线程创建和销毁带来的开销),但这也就意味着线程长时间不会被释放,如果线程一直在运行,虽然Key被GC回收了,但是 Value 一直指向某个强引用对象,那么这个对象就不会被GC回收,从而导致内存泄漏。

解决方法:

使用完ThreadLocal后及时使用remove()释放内存空间,remove() 方法会将当前线程的 ThreadLocalMap 中的所有 key 为 null 的 Entry 全部清除,这样就能避免内存泄漏问题。

3. ThreadLocal线程之间传递

父线程调用了子线程,那么子线程就有可能需要使用父线程中的数据,包括ThreadLocal

  • InheritableThreadLocal    继承自ThreadLocal

原理是每个线程维护两个ThreadLocalMap

普通 ThreadLocal 变量存储在 threadLocals 中,不会被子线程继承。

InheritableThreadLocal 变量存储在 inheritableThreadLocals 中,当 new Thread() 创建一个子线程时,Thread 的 init() 方法会检查父线程是否有 inheritableThreadLocals,如果有,就会拷贝 InheritableThreadLocal 变量到子线程。

  • TransmittableThreadLocal 阿里巴巴开源的工具类,继承并加强了InheritableThreadLocal

通过 装饰器模式 在原有的功能上做增强,以此来实现线程池场景下的 ThreadLocal 值传递。

改造的地方有两处:

  • 实现自定义的 Thread ,在 run() 方法内部做 ThreadLocal 变量的赋值操作。

  • 基于 线程池 进行装饰,在 execute() 方法中,不提交 JDK 内部的 Thread ,而是提交自定义的 Thread 

4. ThreadLocal适用场景

  • 在Web应用中存储用户Session
  • 在数据库操作中存储数据库连接对象,避免多个线程共用一个连接导致事务混乱
  • 用于跨方法、跨类时传递上下文数

缺点:

​分布式系统不适用

​父子线程传递问题

ThreadLocal数据无法持久化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值