美文网首页
java中的ThreadLocal

java中的ThreadLocal

作者: 6cc89d7ec09f | 来源:发表于2018-11-06 13:15 被阅读2次

    ThreadLocal-面试必问深度解析
    https://www.jianshu.com/p/98b68c97df9b
    ThreadLocal内存泄漏真因探究
    https://www.jianshu.com/p/a1cd61fa22da

    image.png

    总结:

    • 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释放掉.所以弱引用是优化了内存泄露问题

    相关文章

      网友评论

          本文标题:java中的ThreadLocal

          本文链接:https://www.haomeiwen.com/subject/klxuxqtx.html