首页 > 其他分享 >ThreadLocal的学习心得

ThreadLocal的学习心得

时间:2023-08-15 21:36:27浏览次数:40  
标签:变量 Thread ThreadLocalMap 学习心得 ThreadLocal 线程 static

ThreadLocal是Java提供的线程本地存储机制,可以实现多线程环境下数据的隔离。主要特点是:

  1. 每个线程都有自己的实例副本,实现了线程的数据隔离。ThreadLocal中存储的值对其他线程都不可见。
  2. 通过get()和set()来读写当前线程的实例副本,避免了线程安全问题。
  3. 本地线程副本通过弱引用持有,在线程消亡后可以自动释放,避免内存泄漏。
  4. 适用于将不安全的变量封装到线程内部、存储线程上下文信息等场景。

注意:

  1. 正确使用remove()释放数据,避免内存泄漏。
  2. 不要对继承ThreadLocal的变量进行修改,每个线程只会复制父类中的初始值。
  3. 避免使用static类型的ThreadLocal变量,这样会导致实例被所有线程共享。
  4. 过度使用ThreadLocal也会导致内存占用过高。

ThreadLocal适合对多线程环境中的变量进行线程隔离。但也需要注意避免内存泄漏等问题。 

  1.为什么可以实现线程的数据隔离?

Thread源码中有这样一句

ThreadLocal.ThreadLocalMap threadLocals = null;

也就是说,在Thread中引用了ThreadLocal中的ThreadLocalMap,

实际上,这也是为什么每一个线程可以进行数据的隔离,因为每一个线程都有自己的ThreadLocalMap,读写相关数据时都是在自己的ThreadLocalMap里面

现在我们来看一看ThreadLocal中的ThreadLocalMap的部分源码

Entry(ThreadLocal<?> k, Object v) {

    super(k);

    value = v;

}

也就是说,实际上threadLocals存放的是<ThreadLocal,value>的键值对

因此,一个ThreadLocal对应一个的value值

如果想要存放多个属性,可以采用下面的方式

ThreadLocal<String>name=new ThreadLocal<>();
ThreadLocal<String>age=new ThreadLocal<>();
或者Map里存放Map
private static final ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<>();
使用如下
Map<String, Object> map = threadLocal.get();

map.put("name", "Alice");

map.put("age", 18);
 
2. 为什么get和set获得的是当前线程的ThreadLocals呢?
源码中的get()有这样的语句
Thread t = Thread.currentThread();
 
ThreadLocalMap map = getMap(t);
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
因为currentThread()的实现内部依赖于JVM的执行引擎,会根据真实的CPU代码执行状态来维护和返回currentThread。
我们可以认为此时获得的一定是当前的线程,通过该线程便可以获得对应的threadLocals.
3.Thread的threadLocals仍然可能出现内存泄漏
当用户没有手动remove(),
这时候Map会出现<null,value>这种无法访问但是又无法被回收的数据
key值为null因为其是弱引用,但是value是强引用所以不会为null,当用户没有手动remove时,value不会消失
如果用户又调用了set,get方法(ThreadLocal提供的对ThreadLocalMap数据操作的接口)
key为null的数据仍然会被回收,即使value不为空
但是当用户长时间没有调用方法并且这种键值对越来越多的时候,可能会导致内存泄漏

4.对于 ThreadLocal 变量,应该避免使用 static 静态类型

  1. static 静态变量会被所有线程共享,而 ThreadLocal 的设计目的就是为每个线程提供独立的变量副本。使用 static 会导致所有线程访问同一个变量,破坏 ThreadLocal 的线程隔离功能。
  2. 不同线程对 static 静态变量的访问存在竞争条件,需要额外的同步措施保证线程安全,而这违背了 ThreadLocal 简化线程安全的初衷。
  3. 每个线程对 static 静态变量的修改会互相影响,难以追踪问题。
  4. static 静态变量的生命周期与应用相同,使用不当容易造成内存泄漏。

所以为了发挥 ThreadLocal 的最大价值,应该定义非静态类型的 ThreadLocal 变量,通常是 private static 的实例变量或方法内部变量。

每个线程只能访问自己的副本,相互隔离,避免了静态变量的弊端。

如有错误,欢迎指出。

 

标签:变量,Thread,ThreadLocalMap,学习心得,ThreadLocal,线程,static
From: https://www.cnblogs.com/leafstar/p/17632497.html

相关文章

  • Syline6.5学习心得-web-创建几何对象
    通过实例说明如何在Skyline中创建圆、文本、多边形等几何要素,设置要素的颜色,要素提示,飞行到几何要素等功能。1.使用的接口    ICreator65:可以创建几何要素、颜色、位置、图层等等(具体请查看api)例如本篇所涉及的要素:CreatePosition,CreateColor,CreateCircle,CreateMessage......
  • 自定义实现可跨线程(线程池)的ThreadLocal
    packageTest0814;importcom.google.common.collect.Maps;importjava.util.HashMap;importjava.util.Map;importjava.util.WeakHashMap;publicclassMyThreadLocal<T>extendsInheritableThreadLocal<T>{//方法1publicstaticfinalInherita......
  • C语言学习心得
    C语言学习心得auto变量和static变量auto变量:每次执行到该变量定义语句时,都会产生一个新的变量,并且重新对此初始化。注意:该关键字在C语言与C++中的语义不同,在C++中是用于变量类型自动推断。为了让类似下面的代码能够在VS2022中运行而不报错,autointa=1;要这样操作:打......
  • 使用 transmittable-thread-local 组件解决 ThreadLocal 父子线程数据传递问题
    在某个项目中,需要使用mybatis-plus多租户功能以便数据隔离,前端将租户id传到后端,后端通过拦截器将该租户id设置到ThreadLocal以便后续使用,代码大体上如下所示:ThreadLocal<Integer>threadLocal=newInheritableThreadLocal<>();threadLocal.set(1);Java 我在Controlle......
  • 谈谈对TransmittableThreadLocal的理解
    前言最近遇到一个问题,公司内部有一个公共的SSO包,用来获取HTTP请求中的登录态,代码中会直接用这个包的方法获取用户登录信息,在代码任意位置直接用SSOUtil.getUser()获取用户信息,在我们一个下载的业务代码中,用到了线程池开启子任务处理请求,结果发现子任务中拿到的用户信息和HTTP请......
  • 线程池使用InheritableThreadLocal踩坑总结
    一、缘起某天测试环境更新后,有小伙伴反应页面会随机性的发生请求参数为空的情况(request.getParamter为空),但是前端的参数是传了的,而且不能稳定重现,需要在页面上经过一番操作之后才会发生,而当问题重现之后,之前那些可用的页面就变得不可用了,然后就会在可用和不可用之间交替........
  • 异步线程变量传递必知必会---InheritableThreadLocal及底层原理分析
    InheritableThreadLocal简介笑傲菌:多线程热知识(一):ThreadLocal简介及底层原理3赞同·0评论文章上一篇文章我们聊到了ThreadLocal的作用机理,但是在文章的末尾,我提到了一个问题,ThreadLocal无法实现异步线程变量的传递。什么意思呢?以下面的代码为例子:@SneakyThrowspublicBo......
  • ThreadLocal实践案例两则
    ThreadLocal是Java中的一个类,全路径:java.lang.ThreadLocal,用于在多线程环境下存储线程本地变量。在多线程应用程序中,不同线程之间共享数据可能会引发线程安全问题。ThreadLocal通过为每个线程创建独立的变量副本,保证了线程间数据的隔离性,从而有效地解决了这一问题。线程之间的数据......
  • 一文让你彻底掌握ThreadLocal
    本文分享自华为云社区《【高并发】一文带你彻底搞懂ThreadLocal》,作者:冰河。我们都知道,在多线程环境下访问同一个共享变量,可能会出现线程安全的问题,为了保证线程安全,我们往往会在访问这个共享变量的时候加锁,以达到同步的效果,如下图所示。对共享变量加锁虽然能够保证线程的安全,但......
  • 一文让你彻底掌握ThreadLocal
    本文分享自华为云社区《【高并发】一文带你彻底搞懂ThreadLocal》,作者:冰河。我们都知道,在多线程环境下访问同一个共享变量,可能会出现线程安全的问题,为了保证线程安全,我们往往会在访问这个共享变量的时候加锁,以达到同步的效果,如下图所示。对共享变量加锁虽然能够保证线程的安......