ThreadLocal-面试必问深度解析
https://www.jianshu.com/p/98b68c97df9b
ThreadLocal内存泄漏真因探究
https://www.jianshu.com/p/a1cd61fa22da
总结:
- Thread内部有一个map结构的存储对象ThreadLocalMap对象,它是ThreadLocal的内部类
- ThreadLocal不存储对象,它相当于一个宝箱的钥匙,宝箱存储在当前线程内部的Map里(ThreadLocalMap).map里的键就是这个ThreadLocal对象.所以说ThreadLocal是开启宝箱的钥匙.
- 同一个ThreadLocal对象可以作为许多线程的钥匙.
造成内存泄露的原因之误区:
- 很多人认为是ThreadLocalMap中的entry继承WeakReference,导致的内存泄露,他们给出的原因是:
引用的key即 ThreadLocal 是弱引用,当key引用的ThreadLocal 在外界没有被强引用,那么下次GC,这个ThreadLocal 一定会被清空,key变成了null.同时这个Thread的生命周期很长(可能是线程池),那么null key对应的value一直得不到GC.
其实原因并不是这样的.仔细看代码就会发现ThreadLocal 在进行 get set remove的时候,都会去把key为null的设置为entity= null
,这就保证了entity和ThreadLocalMap断开了引用,下次GC的时候entity整个都被回收了.
造成内存泄露的原因之真正原因:
- 先看下官方给出的解释:
To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys.
为了处理非常大和生命周期非常长的线程,哈希表使用弱引用作为 key。
线程的生命周期非常长(很可能存在于固定线程池中),而且ThreadLocalMap和这个线程周期一样长
如果ThreadLocal被static修饰,延长了ThreadLocal的生命周期.那么这个线程可能在第一次执行任务时,用这个ThreadLocal作为key存放了一个值,没有被remove掉,并且线程执行结束了.那么这个线程中的ThreadLocalMap里会一直存放之前set进去的value,不会被销毁.导致内存泄露.而如果在某个场景下这个线程拿出了以这个ThreadLocal作为key的值直接用了,那将导致业务逻辑错误.
解决办法
- 每次使用完ThreadLocal,都调用它的remove()方法,清除数据。
为什么ThreadLocal要使用弱引用?
在这种场景下:线程的生命周期非常长
如果强引用了ThreadLocal,这个ThreadLocal外界没有强引用.那么这个线程里面的key一直强引用这个ThreadLocal.方法执行结束了而且没有执行remove方法,ThreadLocal却得不到回收,会导致导致Entry内存泄漏。
如果弱引用了ThreadLocal,这个ThreadLocal外界没有强引用.那么这个线程里面的key一直弱引用这个ThreadLocal.方法执行结束了而且没有执行remove方法.ThreadLocal会被回收,导致线程中存在一个key为null的值.但是在线程下一次执行get/set/remove方法的时候,可能会及时的把key为null的entity释放掉.所以弱引用是优化了内存泄露问题
网友评论