ThreadLocal的学习心得
ThreadLocal是Java提供的线程本地存储机制,可以实现多线程环境下数据的隔离。主要特点是:
- 每个线程都有自己的实例副本,实现了线程的数据隔离。ThreadLocal中存储的值对其他线程都不可见。
- 通过get()和set()来读写当前线程的实例副本,避免了线程安全问题。
- 本地线程副本通过弱引用持有,在线程消亡后可以自动释放,避免内存泄漏。
- 适用于将不安全的变量封装到线程内部、存储线程上下文信息等场景。
注意:
- 正确使用remove()释放数据,避免内存泄漏。
- 不要对继承ThreadLocal的变量进行修改,每个线程只会复制父类中的初始值。
- 避免使用static类型的ThreadLocal变量,这样会导致实例被所有线程共享。
- 过度使用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 静态类型
static 静态变量会被所有线程共享,而 ThreadLocal 的设计目的就是为每个线程提供独立的变量副本。使用 static 会导致所有线程访问同一个变量,破坏 ThreadLocal 的线程隔离功能。
不同线程对 static 静态变量的访问存在竞争条件,需要额外的同步措施保证线程安全,而这违背了 ThreadLocal 简化线程安全的初衷。
每个线程对 static 静态变量的修改会互相影响,难以追踪问题。
static 静态变量的生命周期与应用相同,使用不当容易造成内存泄漏。
所以为了发挥 ThreadLocal 的最大价值,应该定义非静态类型的 ThreadLocal 变量,通常是 private static 的实例变量或方法内部变量。
每个线程只能访问自己的副本,相互隔离,避免了静态变量的弊端。
如有错误,欢迎指出。
ThreadLocal的学习心得的更多相关文章
- folly学习心得(转)
原文地址: https://www.cnblogs.com/Leo_wl/archive/2012/06/27/2566346.html 阅读目录 学习代码库的一般步骤 folly库的学习心得 ...
- 我的MYSQL学习心得(一) 简单语法
我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(二) 数据类型宽度
我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(三) 查看字段长度
我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(四) 数据类型
我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(五) 运算符
我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...
- 我的MYSQL学习心得(六) 函数
我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
- 我的MYSQL学习心得(七) 查询
我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
- 我的MYSQL学习心得(八) 插入 更新 删除
我的MYSQL学习心得(八) 插入 更新 删除 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得( ...
- 我的MYSQL学习心得(九) 索引
我的MYSQL学习心得(九) 索引 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
随机推荐
- 2022-07-07:原本数组中都是大于0、小于等于k的数字,是一个单调不减的数组, 其中可能有相等的数字,总体趋势是递增的。 但是其中有些位置的数被替换成了0,我们需要求出所有的把0替换的方案数量:
2022-07-07:原本数组中都是大于0.小于等于k的数字,是一个单调不减的数组, 其中可能有相等的数字,总体趋势是递增的. 但是其中有些位置的数被替换成了0,我们需要求出所有的把0替换的方案数量: ...
- 2021-03-06:go中,公共变量是协程安全吗?赋值操作是原子的吗?为什么?
2021-03-06:go中,公共变量是协程安全吗?赋值操作是原子的吗?为什么? 福哥答案2021-03-06: 这是面试中被问到的.实力有限,真正的答案还不知道.我的想法是a=1是原子操作,a=b不 ...
- 2021-07-17:一个不含有负数的数组可以代表一圈环形山,每个位置的值代表山的高度。比如, {3,1,2,4,5}、{4,5,3,1,2}或{1,2,4,5,3}都代表同样结构的环形山。山峰A和山
2021-07-17:一个不含有负数的数组可以代表一圈环形山,每个位置的值代表山的高度.比如, {3,1,2,4,5}.{4,5,3,1,2}或{1,2,4,5,3}都代表同样结构的环形山.山峰A和山 ...
- web自动化08-下拉选择框、弹出框、滚动条
1.下拉选择框操作 下拉框就是HTML中<select>元素: 先列需求: 需求:使用'注册A.html'页面,完成对城市的下拉框的操作 1).选择'广州' 2).暂停2秒,选择'上海 ...
- Mybatis的ResultMap对column和property的理解
Mybatis的ResultMap对column和property的理解 首先,先看看这张图,看能不能一下看明白: select元素有很多属性(这里说用的比较多的): id:命名空间唯一标识,可以被用 ...
- 2023-06-21:redis中什么是BigKey?该如何解决?
2023-06-21:redis中什么是BigKey?该如何解决? 答案2023-06-21: 什么是bigkey bigkey是指存储在Key-Value数据库中的键对应的值所占用的内存空间较大.举 ...
- Linux系统运维之Web服务器Nginx安装
一.介绍 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.本文先整理web服务器内容. 二.环境及软件版本 操作 ...
- vCenter报错:Vmware vAPI Endpoint
vCenter报错:Vmware vAPI Endpoint 问题现象: 平台警报1:设备管理运行状况警报 平台警报2:Vmware vAPI Endpoint服务运行状况警报 vcenter版本:v ...
- 无缝数据转换!使用C++ 实现 Excel文件与CSV之间的相互转换
CSV格式是一种通用的文本文件格式,可在多个应用程序之间共享和使用.相比之下,Excel文件是一种电子表格格式,通常只能在Microsoft Excel中编辑和查看.因此,将Excel文件转换为CSV ...
- PHP file_put_contents()写入配置文件
php把提交的数据写入到配置文件中 在后台可以设置网站的基本信息,例如:title,keywords,copyright.等信息,这些信息只是一条数据,存入数据库耗费资源,直接写入到php文件中. 创 ...