ThreadLocal为什么会出现内存泄漏,你真的知道吗?
1 前言
大家想要搞清楚这个问题,就必须知道内存泄漏和内存溢出的区别
内存泄漏:不就被使用的对象或者变量无法被回收
内存溢出:没有剩余的空间来创建新的对象
2 ThreadLocal进行线程隔离的小示例
同一个threadlocal对象,不同线程之间存储的值是获取不到的
public class QuThreadLocal { static ThreadLocal<Wolf> t1 = new ThreadLocal<>(); public static void main(String[] args) { new Thread(()->{ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } t1.set(new Wolf("小王")); System.out.println(t1.get()); t1.remove(); }).start(); new Thread(()->{ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(t1.get()); }).start(); } }
控制台输出:
可以发现在不同的线程里面放置东西,其它线程里面是找不到的。
解析原因,观察是如何向threadlocal中放置值的:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
1)先获取当前线程t,然后根据t获取threadmap对象
2)判断map是否为null,map不为null时,将当前threadllocal对象作为key,想要设置的值作为value放置其中,否则就创建一个map。创建map的key值与上相同。
这也表明了,存储的值只有当前线程才能够获取到。
3 原因
threadlocal内部结构:
造成内存泄漏的原因:
由于Entry中的value是强引用,key是弱引用;当垃圾回收器回收threadlocal时,由于value是强引用,不能被回收,所以造成了内存泄漏。
因此,ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应的key就会导致内存泄漏,而并不是因为弱引用。
解决方案一:扩大成员变量Threadlocal的一个作用域,避免被GC回收(不推荐)
解决方案二:每次使用完threadlocal之后,就调用remove方法去移除对应的数据(推荐)
上一篇:
通过多线程提高代码的执行效率例子
下一篇:
idea控制台输出中文乱码解决