【ThreadLocal详解】

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


ThreadLocal

  ThreadLocal是一个用于实现线程数据隔离的一个类,每个线程访问时,通过Get、Set方法都会产生一个属于该线程的局部变量副本,当线程结束时,ThreadLocal及变量随着线程一起被回收。


ThreadLocal的作用

总的来说,ThreadLocal有三大用途:

  1. 保存线程上下文信息,在任何地方都可以获取(通过static关键字)
     我们可以使用static关键字,在任意地方都可以对该ThreadLocal进行获取、设置。
     例如Spring中的事务,用ThreadLocal存储了连接对象,保证一次事务的所有操作都在同一连接上。
     
  2. 线程安全,避免某些情况下需要保持同步而带来的性能损失
  
  3. 线程之间数据隔离

ThreadLocal的原理

  ThreadLocal虽然叫线程局部变量,但是它不存储任何数据,它只是一个壳子,真正的存储结构是在ThreadLocal中有一个ThreadLocalMap的一个内部类,而这个内部类却被Thread定义为了成员变量。
而ThreadLocal本身并不存储值,它只是作为key存储在Thread对象中的ThreadLocalMap中,而value则是我们存储的变量。
那么,既然真正存储数据的是Thread对象中的ThreadLocalMap,每个线程都是自己的Thread对象,那么也就达成了线程私有变量以及数据隔离。

public void set(T value) {
    // 返回当前 ThreadLocal 所在的线程
    Thread t = Thread.currentThread();
    // 返回当前线程持有的map
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 如果 ThreadLocalMap 不为空,则直接存储<ThreadLocal, T>键值对
        map.set(this, value);
    } else {
        // 否则,需要为当前线程初始化 ThreadLocalMap,并存储键值对 <this, firstValue>
        createMap(t, value);
    }
}

  源码解析:

  1. Set() 方法

threadlocal,java,jvm,面试

主要有几个步骤:

  1. 获取当前线程
  2. 将当前线程传入getMap()方法,获取ThreadLocalMap对象
  3. 设置 key 为 [当前ThreadLocal对象],value为我们设定的值。
  4. 如果Map不存在,则创建一个Map

  这时候,我们肯定纠结,这个Map到底是什么?我们接着看:

    进入getMap() 方法:

threadlocal,java,jvm,面试

    这是我们可以看到,该方法返回了当前线程的 threadLocals 属性,那我们再看看是什么:

threadlocal,java,jvm,面试

    原来是在Thread对象中,看到这里是不是有种明悟,原来:

  1. set() 方法中,首先获取当前线程。
  2. 获取该线程对象中的 threadLocals 属性。
ThreadLocalMap map = getMap(t))
  1. 如果该属性存在,则往其中添加元素。
map.set(this, value)
  1. 而不存在的话,则初始化该属性 threadLocals,并将值添加进去作为初始值
createMap(t, value);

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

    我们都知道,每个线程在Java内部都表现为一个Thread对象,而每个Thread对象都拥有 threadLocals 属性,在线程调用了 set() 方法后,会初始化该属性,并且将本线程所属的元素存入进去,这样就造成了数据隔离,每个线程有自己的数据。


    实战验证

  • 没有使用ThreadLocal的情况:

threadlocal,java,jvm,面试

    我们都知道,SimpleDateFormat因为内部使用了日历对象Calendar,导致不能将其作为线程共享对象,会引发线程安全问题。
因为只有一个Calendar实例,而多线程共享该实例

threadlocal,java,jvm,面试

    结果(线程1及线程2运行时设置的时间被线程3覆盖,导致出现了错误的结果):

threadlocal,java,jvm,面试


  • 使用ThreadLocal:

threadlocal,java,jvm,面试

    结果(因为每个线程都存着自己的那份SimpleDateFormat对象,所以不会出现并发情况):

threadlocal,java,jvm,面试


    Debug

     线程1拥有的:
threadlocal,java,jvm,面试

     线程2拥有的:
threadlocal,java,jvm,面试

     线程3拥有的:
threadlocal,java,jvm,面试

    可以看到,每个线程都拥有自己的SimpleDateFormat对象。

ThreadLocal内存泄漏

  ThreadLocal内存泄漏指的是:ThreadLocal对象被回收了,但是线程内的ThreadLocalMap成员与线程一样继续存在着,它不会回收,就出现了一个现象,就是ThreadLocalMap的key没了,Map没有了指向,但value还在,key的引用一直在就造成了内存泄漏。

  而为什么ThreadLocal对象会被回收呢,因为它是弱引用。它的生命周期更短,会在一次GC后回收掉。

threadlocal,java,jvm,面试

  所以使用其最好的方式是:用完了,将其remove掉,从Thread.threadLocals(Map)中删除即可。

总结

  总的来说,ThreadLocal通过避免并发保证数据安全,将数据绑定到Thread对象上,保证了数据隔离。而在使用完毕后,必须手动将值进行remove(),否则,当线程一直运行时,容易出现内存泄漏风险。文章来源地址https://www.toymoban.com/news/detail-661103.html

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

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

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

相关文章

  • 《面试1v1》ThreadLocal

    我是 javapub,一名 Markdown 程序员从👨‍💻,八股文种子选手。 面试官 : 你好,请问你对 ThreadLocal 有了解吗? 候选人: 您好,我知道 ThreadLocal 是一个 Java 中的类,它可以让每个线程都拥有自己的变量副本,从而避免了线程安全问题。 面试官 : 非常好,那你能否详细介绍

    2024年02月06日
    浏览(50)
  • 面试再也不怕问ThreadLocal了

    要解决多线程并发问题,常见的手段无非就几种。加锁,如使用synchronized,ReentrantLock,加锁可以限制资源只能被一个线程访问;CAS机制,如AtomicInterger,AtomicBoolean等原子类,通过自旋的方式来尝试修改资源;还有本次我们要介绍的ThreadLocal类,通过为每个线程维护一个变量副本

    2024年02月14日
    浏览(38)
  • 【ThreadLocal详解】

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

    2024年02月12日
    浏览(38)
  • ThreadLocal 详解

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

    2023年04月08日
    浏览(32)
  • ThreadLocal 本地线程变量详解

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

    2024年02月05日
    浏览(47)
  • 史上最全ThreadLocal 详解(二)

    ThreadLocal 内存泄露的原因及处理方式 目录 1、ThreadLocal 使用原理 2、ThreadLocal 内存泄露的原因 3、 为什么不将key设置为强引用 3.1 、key 如果是强引用 3.2、key 如果是强引用 3.3  那么为什么 key 要用弱引用 3.4 如何正确的使用ThreadLocal        前文我们讲过ThreadLocal的主要用途是

    2024年02月02日
    浏览(57)
  • 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)
  • 《吊打面试官系列》从源码全面解析 ThreadLocal 关键字的来龙去脉

    👏作者简介:大家好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主 📕系列专栏:Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙、Spring从成神到升仙系列 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一

    2023年04月23日
    浏览(67)
  • java 并发 随笔7 ThreadLocal源码走读

    可以看到 Thread 是内部是维护了局部变量的(thread-local-map) 很多的细节都在代码块中备注了

    2024年02月13日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包