ThreadLocal内存泄漏问题
一、对ThreadLocal的理解
- ThreadLocal提供了线程本地变量,它可以保证访问到的变量属于当前线程,每个线程都保存有一个变量副本,每个线程的变量都不同。
- ThreadLocal相当于提供了一种线程隔离,将变量与线程相绑定。
- ThreadLocal适用于多线程的情况下,可以实现传递数据实现线程隔离。
二、ThreadLocal基本API
- new ThreadLocal() -----创建ThreadLocal
- set设置当前线程绑定的局部变量
- get获取当前线程绑定的局部变量
三、哪些地方使用ThreadLocal
- Spring事务模板类 (设计模式的模板方法)
- 获取httprequest
SpringMVC获取httprequest对象,SpringMVC封装将httprequest对象缓存在ThreadLocal当前线程中, - Aop拦截请求
四、ThreadLocal 底层实现原理
- 在每个线程中都有自己独立的ThreadLocalMap对象,Entry对象。
- 如果当前线程对应的ThreadLocalMap对象为空的情况下,则创建ThreadLocalMap对象,并赋值键值对。
- key为当前new ThreadLocal对象,value为object变量值。
ThreadLocal 中set方法与get方法源码
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, 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();
}
五、为什么线程缓存的是ThreadLocalMap对象
- ThreadLocalMap可以存放多个不同的ThreadLocal对象;
- 每个ThreadLocal对象只能缓存一个变量值。
- ThreadLocalMap <ThreadLocal,value> threadLocalMap = new ThreadLocalMap(this, firstValue);
this代表当前线程ThreadLocal;
六、强、软、弱、虚引用的区别
1. 强引用
当内存不足时,JVM开始进行GC(垃圾回收),对于强引用对象,就算是出现了OOM(Out of memory, 内存溢出)也不会对该对象进行回收,死都不回收。
2. 软引用
当系统内存充足的时候,不会回收;当系统内存不足时,他会被回收,软引用通常用在对内存敏感的的程序中,比如高速缓存就用到软引用,内存够用时就保留,不够时就回收。
3. 弱引用
弱引用需要用到java.lang.ref.WeakReference类来实现,它比软引用的生存周期更短。对于只有弱引用的对象来说,只要有垃圾回收,不管JVM的内存空间够不够用,都会回收该对象占用的内存空间。
sql使用弱引用
4. 虚引用
虚引用需要用java.lang.ref.PhantomReference类来实现,虚引用就是形同虚设。与其他几种引用不同,虚引用并不会决定对象的声明周期。
七、ThreadLocal 如何引发内存泄漏问题
1. 内存泄漏
- 表示申请了内存,但是该内存一直无法释放。
2. 内存溢出
- 申请内存时,发现申请内存不足,就会报错内存溢出的问题。
因为每个线程都有自己独立的ThreadLocalMap对象,key为ThreadLocal ,value是为变量值;
key为ThreadLocal 作为entry对象的key,是弱引用,当ThreadLocal 指向null的时候,entry对象中的key变为null,该对象一直无法被垃圾收集机制回收,一直占用到系统内存,有可能会发生内存泄漏的问题。
八、如何防御ThreadLocal 内存泄漏问题
- 可以自己调用remove方法将不要的数据移除,避免内存泄漏问题,
- 每次在做set方法的时候会清除之前key为null。
九、ThreadLocal 采用弱引用而不是强引用
如果key是为强引用,将ThreadLocal 的引用指向为null,但是每个线程中有自己独立ThreadLocalMap还一直继续持有该对象,但是ThreadLocal 对象不会被回收,就会发生ThreadLocal 内存泄漏问题。
:- 到这里相信你已经get到了