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

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

注意:

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

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

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

  Thread源码中有这样一句

  1. ThreadLocal.ThreadLocalMap threadLocals = null;

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

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

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

  1. Entry(ThreadLocal<?> k, Object v) {
  2.   super(k);
  3.   value = v;
  4. }

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

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

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

  1. ThreadLocal<String>name=new ThreadLocal<>();
  2. ThreadLocal<String>age=new ThreadLocal<>();

  或者Map里存放Map

  1. private static final ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<>();

  使用如下

  1. Map<String, Object> map = threadLocal.get();
  2.  
  3. map.put("name", "Alice");
  4.  
  5. map.put("age", 18);

2. 为什么get和set获得的是当前线程的ThreadLocals呢?
  源码中的get()有这样的语句

  1. Thread t = Thread.currentThread();
  2.  
  3. ThreadLocalMap map = getMap(t);
  4. ThreadLocalMap getMap(Thread t) {
  5.   return t.threadLocals;
  6. }

  因为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 静态类型

  static 静态变量会被所有线程共享,而 ThreadLocal 的设计目的就是为每个线程提供独立的变量副本。使用 static 会导致所有线程访问同一个变量,破坏 ThreadLocal 的线程隔离功能。
  不同线程对 static 静态变量的访问存在竞争条件,需要额外的同步措施保证线程安全,而这违背了 ThreadLocal 简化线程安全的初衷。
  每个线程对 static 静态变量的修改会互相影响,难以追踪问题。
  static 静态变量的生命周期与应用相同,使用不当容易造成内存泄漏。
  所以为了发挥 ThreadLocal 的最大价值,应该定义非静态类型的 ThreadLocal 变量,通常是 private static 的实例变量或方法内部变量。

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

  如有错误,欢迎指出。

ThreadLocal的学习心得的更多相关文章

  1. folly学习心得(转)

    原文地址:  https://www.cnblogs.com/Leo_wl/archive/2012/06/27/2566346.html   阅读目录 学习代码库的一般步骤 folly库的学习心得 ...

  2. 我的MYSQL学习心得(一) 简单语法

    我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  3. 我的MYSQL学习心得(二) 数据类型宽度

    我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  4. 我的MYSQL学习心得(三) 查看字段长度

    我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  5. 我的MYSQL学习心得(四) 数据类型

    我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...

  6. 我的MYSQL学习心得(五) 运算符

    我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  7. 我的MYSQL学习心得(六) 函数

    我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  8. 我的MYSQL学习心得(七) 查询

    我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  9. 我的MYSQL学习心得(八) 插入 更新 删除

    我的MYSQL学习心得(八) 插入 更新 删除 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得( ...

  10. 我的MYSQL学习心得(九) 索引

    我的MYSQL学习心得(九) 索引 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

随机推荐

  1. 2022-03-04:爱吃香蕉的珂珂。 珂珂喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。 珂珂可以决定她吃香蕉的速度 K (单位:根

    2022-03-04:爱吃香蕉的珂珂. 珂珂喜欢吃香蕉.这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉.警卫已经离开了,将在 H 小时后回来. 珂珂可以决定她吃香蕉的速度 K (单位:根 ...

  2. 2022-01-29:连接词。 给你一个 不含重复 单词的字符串数组 words ,请你找出并返回 words 中的所有 连接词 。 连接词 定义为:一个完全由给定数组中的至少两个较短单词组成的字符串

    2022-01-29:连接词. 给你一个 不含重复 单词的字符串数组 words ,请你找出并返回 words 中的所有 连接词 . 连接词 定义为:一个完全由给定数组中的至少两个较短单词组成的字符串 ...

  3. 【GiraKoo】Android监听屏幕尺寸变化通知

    [GiraKoo]Android监听屏幕尺寸变化通知 Android系统中存在多种情况可能导致屏幕尺寸发生变化.例如:横竖屏切换,虚拟按键,分屏,键盘弹出等. App有的时候需要了解屏幕的真实尺寸,D ...

  4. AIGC持续火爆大模型争相推出,庞大市场造就算力供应模式演变

    本图由AI生成 黄仁勋说的AI发展迎来iPhone时刻,对NVIDIA有什么影响? 文/王吉伟 近期的AIGC领域仍旧火爆异常. 但火的不只是AIGC应用,还有巨头之间的AI竞赛,以及接连不断上新的A ...

  5. 【HarmonyOS】元服务和APP的相互跳转、相互成就

    ​ [关键字] 卡片.跳转.加桌 [背景介绍] 随着鸿蒙生态的发展,各种类型的应用都已经可以在Harmony OS上无差异的运行,面对鸿蒙新兴元服务的兴起,各大厂家可能都在考虑一个问题:如果已经有AP ...

  6. 【Python入门教程】批量修改文件名,批量移动文件

            Python提供了高效的高级数据结构,还能简单有效地面向对象编程.Python语法和动态类型,以及解释型语言的本质,使它成为多数平台上写脚本和快速开发应用的编程语言.本篇文章是&quo ...

  7. 如何使用libavfilter库给输入文件input.yuv添加视频滤镜?

    一.视频滤镜初始化 本次代码实现的是给输入视频文件添加水平翻转滤镜,在视频滤镜初始化部分我们可以分为以下几步进行: 1.创建滤镜图结构 视频滤镜功能最核心的结构为滤镜图结构,即AVFilterGrap ...

  8. charAt和substring方法的使用

    charAt和substring方法的使用 一.charAt的相关应用 1.charAt方法 charAt截取单个字符,参数index范围从0开始,length-1截止. 2.语法 public ch ...

  9. 暗黑王者|ZEGO 低照度图像增强技术解析

    在低光照的夜间,摄像头采集的画面通常是一片昏暗,画面清晰度要远远低于肉眼.而随着实时音视频应用技术的发展,我们已经看到了各种画质增强的视频增强技术,那么是否存在一种技术,可以使视频在低光照条件下看起来 ...

  10. 正确处理 CSV 文件的引号和逗号

    CSV(Comma-Separated Values,逗号分割值),就是用纯文本的形式存储表格数据,最大的特点就是方便. 作为开发,我们经常面临导数据的问题,特别是后台系统,产品或者运营的同事常常会提 ...