ThreadLocal浅入浅出

一、概述

ThreadLocal类用来提供线程内部的局部变量。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量,ThreadLocal实例通常来说都是private static类型。
总结:ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。

ThreadLocal的主要应用场景为按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。例如:同一个网站登录用户,每个用户服务器会为其开一个线程,每个线程中创建一个ThreadLocal,里面存用户基本信息等,在很多页面跳转时,会显示用户信息或者得到用户的一些信息等频繁操作,这样多线程之间并没有联系而且当前线程也可以及时获取想要的数据。

This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).

核心意思是

ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。ThreadLocal 变量通常被private static修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。

总的来说,ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景。后文会通过实例详细阐述该观点。另外,该场景下,并非必须使用 ThreadLocal ,其它方式完全可以实现同样的效果,只是 ThreadLocal 使得实现更简洁。

原理

  • 既然我们明白了ThreadLocal的作用那我们的试着想一下他是如何实现的呢?? 他是同一个线程共享一个变量。那么我们是不是首先要找个东西来存储这个变量呢?存储的容积也就那几种,Map,list,等。那就用Map吧,一个Key一个Value,value来存储共享的变量,那么这个key就必须能保证是这个线程,那我们就把线程自己存储进去呗,还有就是这个map放在哪里呢??还有并发问题,内存泄露问题,等等。。。。想不下去那接下来我们来看看ThreadLocal的源码是如何实现的呢?
    -在JDK中ThreadLocal的map是写在Thread中的,每个Thread都会有自己的Map(ThreadLOcalMap),从而就解决了因并发问题导致的Map线程不安全的问题(具体的内容可以深入去看一下ThreadLocal的源码)
  • 如果这个ThreadLocals这个map和具体的实例是有映射的,所以说有可能会导致内存泄露的问题,在源码中会将这个ThreadLocal这个key为设置为弱引用,在java中弱引用的特点是只要发生GC 就会将这个变量清理掉。(tips:硬软弱虚java中的四种引用方式)。大概在这个提一下了解具体原因请自行看源码

总结

  • ThreadLocal 并不解决线程间共享数据的问题
  • ThreadLocal 通过隐式的在不同线程内创建独立实例副本避免了实例线程安全的问题
    每个线程持有一个 Map 并维护了 ThreadLocal 对象与具体实例的映射,该 Map 由于只被持有它的线程访问,故不存在线程安全以及锁的问题
  • ThreadLocalMap 的 Entry 对 ThreadLocal 的引用为弱引用,避免了 ThreadLocal 对象无法被回收的问题
  • ThreadLocalMap 的 set 方法通过调用 replaceStaleEntry 方法回收键为 null 的 Entry 对象的值(即为具体实例)以及 Entry 对象本身从而防止内存泄漏
    ThreadLocal 适用于变量在线程间隔离且在方法间共享的场景
原创文章 92 获赞 11 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_40413961/article/details/105501384