史上最全ThreadLocal 详解(二)

这篇具有很好参考价值的文章主要介绍了史上最全ThreadLocal 详解(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

ThreadLocal 内存泄露的原因及处理方式

目录

1、ThreadLocal 使用原理

2、ThreadLocal 内存泄露的原因

3、 为什么不将key设置为强引用

3.1 、key 如果是强引用

3.2、key 如果是强引用

3.3  那么为什么 key 要用弱引用

3.4 如何正确的使用ThreadLocal


1、ThreadLocal 使用原理

       前文我们讲过ThreadLocal的主要用途是实现线程间变量的隔离,表面上他们使用的是同一个ThreadLocal, 但是实际上使用的值value却是自己独有的一份。用一图直接表示threadlocal 的使用方式。
史上最全threadlocal 详解(二),java并发编程,java 学习,java,开发语言

图1

从图中我们可以当线程使用threadlocal 时,是将threadlocal当做当前线程thread的属性ThreadLocalMap 中的一个Entry的key值,实际上存放的变量是Entry的value值,我们实际要使用的值是value值。value值为什么不存在并发问题呢,因为它只有一个线程能访问。threadlocal我们可以当做一个索引看待,可以有多个threadlocal 变量,不同的threadlocal对应于不同的value值,他们之间互不影响。ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。

2、ThreadLocal 内存泄露的原因  

 Entry将ThreadLocal作为Key,值作为value保存,它继承自WeakReference,注意构造函数里的第一行代码super(k),这意味着ThreadLocal对象是一个「弱引用」。可以看图1.

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;
    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

主要两个原因
1 . 没有手动删除这个 Entry
2 . CurrentThread 当前线程依然运行

        第一点很好理解,只要在使用完下 ThreadLocal ,调用其 remove 方法删除对应的 Entry ,就能避免内存泄漏。
        第二点稍微复杂一点,由于ThreadLocalMap 是 Thread 的一个属性,被当前线程所引用,所以ThreadLocalMap的生命周期跟 Thread 一样长。如果threadlocal变量被回收,那么当前线程的threadlocal 变量副本指向的就是key=null, 也即entry(null,value),那这个entry对应的value永远无法访问到。实际私用ThreadLocal场景都是采用线程池,而线程池中的线程都是复用的,这样就可能导致非常多的entry(null,value)出现,从而导致内存泄露。
综上, ThreadLocal 内存泄漏的根源是:
    由于ThreadLocalMap 的生命周期跟 Thread 一样长,对于重复利用的线程来说,如果没有手动删除(remove()方法)对应 key 就会导致entry(null,value)的对象越来越多,从而导致内存泄漏.

3、 为什么不将key设置为强引用

3.1 、key 如果是强引用

     那么为什么ThreadLocalMap的key要设计成弱引用呢?其实很简单,如果key设计成强引用且没有手动remove(),那么key会和value一样伴随线程的整个生命周期。

   1、假设在业务代码中使用完ThreadLocal, ThreadLocal ref被回收了,但是因为threadLocalMap的Entry强引用了threadLocal(key就是threadLocal), 造成ThreadLocal无法被回收。在没有手动删除Entry以及CurrentThread(当前线程)依然运行的前提下, 始终有强引用链CurrentThread Ref → CurrentThread →Map(ThreadLocalMap)-> entry, Entry就不会被回收( Entry中包括了ThreadLocal实例和value), 导致Entry内存泄漏也就是说: ThreadLocalMap中的key使用了强引用, 是无法完全避免内存泄漏的。请结合图1看。

3.3  那么为什么 key 要用弱引用

     事实上,在 ThreadLocalMap 中的set/getEntry 方法中,会对 key 为 null(也即是 ThreadLocal 为 null )进行判断,如果为 null 的话,那么会把 value 置为 null 的.这就意味着使用threadLocal , CurrentThread 依然运行的前提下.就算忘记调用 remove 方法,弱引用比强引用可以多一层保障:弱引用的 ThreadLocal 会被回收.对应value在下一次 ThreadLocaI 调用 get()/set()/remove() 中的任一方法的时候会被清除,从而避免内存泄漏.


 

3.4 如何正确的使用ThreadLocal

 1、将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,由于一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,然后remove它,防止内存泄露


 2、每次使用完ThreadLocal,都调用它的remove()方法,清除数据。
 文章来源地址https://www.toymoban.com/news/detail-786745.html

到了这里,关于史上最全ThreadLocal 详解(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • (线程池)多线程使用场景--es数据批量导入、数据汇总、异步调用;如何控制某个方法允许并发访问线程的数量;对ThreadLocal的理解及实现原理、源码解析、ThreadLocal的内存泄露问题

    CountDownLatch(闭锁/倒计时锁) 用来进行线程同步协作,等待所有线程完成倒计时(一个或者多个线程,等待其他多个线程完成某件事情之后才能执行) 其中构造参数用来初始化等待计数值 await() 用来等待计数归零 countDown() 用来让计数 减一 多线程使用场景一:( es数据批量导

    2024年04月25日
    浏览(69)
  • ThreadLocal 详解

    ThreadLocal类用来提供线程内部的局部变量,不同的线程之间不会相互干扰 这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量 在线程的生命周期内起作用,可以减少同一个线程内多个函数或组件之间一些公共变量传递的

    2023年04月08日
    浏览(31)
  • 【ThreadLocal详解】

      ThreadLocal是一个用于实现线程数据隔离的一个类,每个线程访问时,通过Get、Set方法都会产生一个属于该线程的局部变量副本,当线程结束时,ThreadLocal及变量随着线程一起被回收。 总的来说,ThreadLocal有三大用途:   ThreadLocal虽然叫线程局部变量,但是它不存储任何数据

    2024年02月12日
    浏览(38)
  • ThreadLocal 本地线程变量详解

    ThreadLocal 意为本地线程变量,即该变量只属于当前线程,对其他线程隔离 我们知道,一个普通变量如果被多线程访问会存在存在线程安全问题,这时我们可以使用 Synchronize 来保证该变量某一时刻只能有一个线程访问,从而解决并发安全问题 但如果这个变量并不需要被共享,

    2024年02月05日
    浏览(47)
  • 导致JVM内存泄露的ThreadLocal详解

    很常见的关于ThreadLocal的面试题的问法: 1.说说你对ThreadLocal的理解。 2.ThreadLocal 是什么?有哪 些使用场景?什么是线程局部变量? 3.ThreadLocal内存泄漏分析与解决方案。 ps:想理解好ThreadLocal,必须先得理解好JVM的内存模型 多个线程共同操作一个共享变量,一定会引发并发问

    2024年02月09日
    浏览(49)
  • java ThreadLocal

    上面三行代码分别是定义、赋值和取值。 介绍: 我们只需要实例化对象一次,并且也不需要知道它是被哪个线程实例化。虽然所有的线程都能访问到这个ThreadLocal实例,但是每个线程却只能访问到自己通过调用ThreadLocal的set()方法设置的值。即使是两个不同的线程在同一个T

    2024年02月14日
    浏览(41)
  • Java——》ThreadLocal

    推荐链接:     总结——》【Java】     总结——》【Mysql】     总结——》【Redis】     总结——》【Kafka】     总结——》【Spring】     总结——》【SpringBoot】     总结——》【MyBatis、MyBatis-Plus】     总结——》【Linux】     总结——》【MongoDB】    

    2024年02月09日
    浏览(91)
  • java面试之ThreadLocal问题

    什么是ThreadLocal,它的基本用法是什么  简单来说就是能在多线程中保持变量独立的线程对象 不用Threadlocal多线程访问同一个变量会出现的问题 下面直接已经线程混乱   一般来说我们可以用锁来解决,比如引入synchronized,这里我们先不用锁,我们用ThreadLocal这个类去解决 Thr

    2024年02月09日
    浏览(43)
  • Java中ThreadLocal的用法和原理

    隔离各个线程间的数据 避免线程内每个方法都进行传参,线程内的所有方法都可以直接获取到 ThreadLocal 中管理的对象。 使用 junit 进行测试: 结果如下,可以看到没有被 ThreadLocal 管理的变量已经无法匹配正确的format。 从 ThreadLocal 中获取数据的过程: 先获取对应的线程。

    2023年04月12日
    浏览(42)
  • 【Java】线程数据共享和安全 -ThreadLocal

     🎄欢迎来到@边境矢梦°的csdn博文🎄  🎄本文主要梳理线程数据共享和安全 -ThreadLocal🎄 🌈我是边境矢梦°,一个正在为秋招和算法竞赛做准备的学生🌈 🎆喜欢的朋友可以关注一下 🫰🫰🫰 ,下次更新不迷路🎆 Ps: 月亮越亮说明知识点越重要 (重要性或者难度越大)🌑🌒

    2024年02月09日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包