网站首页 > 精选教程 正文
ThreadLocal是实现Java并发编程非常重要的一个组件,也是大厂喜欢考察的内容,下面我就全面来详解ThreadLocal@mikechen
本篇已收于mikechen原创超30万字《阿里架构师进阶专题合集》里面。
ThreadLocal
ThreadLocal提供了线程的本地变量,是 Java 中用于实现线程局部变量的类,它提供了线程内部的独立变量。
即即每个线程都有一个独立的"变量副本",不会与其他线程的"变量副本"产生冲突。
如下图所示:
每个线程都有自己的独立资源,可以通过 ThreadLocal 对象访问它自己的独立变量。
ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。
ThreadLocal主要用于:解决多线程并发时访问共享变量的问题,主要是做数据隔离。
ThreadLocal原理
ThreadLocal原理:ThreadLocal相当于维护了一个map,key就是当前的线程,value就是需要存储的对象。
这个 Map 不是直接使用 HashMap ,而是 ThreadLocal 实现的一个叫做 ThreadLocalMap 的静态内部类,用来存变量。
它的大概结构如下图所示:
ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的核心存储结构,类似于 HashMap,但设计上有所不同:
ThreadLocalMap 是 ThreadLocal 的内部静态类,是一个自定义的哈希表,专门用于存储与 ThreadLocal 关联的数据。
每个线程都持有一个 ThreadLocalMap 实例,以存储它的 ThreadLocal 变量和对应的值。
ThreadLocalMap是一个Map,key是ThreadLocal,value是Object。
Entry 类
除此之外,ThreadLocalMap内部持有一个 Entry[] 类型的数组 table,每个数组成员都是一个键值对,Entry数组是真正承载数据的地方。
ThreadLocalMap.Entry 继承自 Java 标准库中的 WeakReference<ThreadLocal<?>>,它的核心结构如下:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
//key就是一个弱引用
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
Entry继承自WeakReference,每个Entry 的 key 都是一个 ThreadLocal 对象的弱引用,Java 中的弱引用允许对一个对象的引用在没有强引用的情况下,被垃圾回收器回收。
value 是Object 类型,是强引用,ThreadLocalMap 中可以包含多个ThreadLocal对象。
如下图所示:
实际上,每一个ThreadLocal对象都包含了一个独一无二的threadLocalHashCode值,使用这个值就可以在KV数组中找到对应的本地变量。
key是ThreadLocal对象的弱引用,之所以使用 WeakReference 类型作为ThreadLocal对象的引用,是出于垃圾回收考虑。
不过需要注意的是,虽然key值是弱引用,不影响ThreadLocal对象回收,但value值是强引用。
当ThreadLocal被回收,value对象不会被回收,可能会引发内存泄漏。
所以,记得要调用 remove() 方法,避免内存泄露。
ThreadLocal使用
ThreadLocal的用法,这个类提供thread-local变量,这些变量与线程的局部变量不同,每个线程都保存一份改变量的副本,可以通过get、或者set方法访问。
如下所示:
//创建
private ThreadLocal threadLocal = new ThreadLocal();
//一旦创建了ThreadLocal,就可以使用它的set()方法设置要存储在其中的值
threadLocal.set("A thread local value");
//获取值
String threadLocalValue = (String) threadLocal.get();
//移除一个值
threadLocal.remove();
ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的,通过get和set方法就可以得到当前线程对应的值。
由于ThreadLocal里设置的值,只有当前线程自己看得见,这意味着你不可能通过其他线程为它初始化值,为了弥补这一点,ThreadLocal提供了一个withInitial()方法统一初始化所有线程的ThreadLocal的值。
如下所示:
private ThreadLocal<Integer> localInt = ThreadLocal.withInitial(() -> 18);
上述代码将ThreadLocal的初始值设置为18,这对全体线程都是可见的。
ThreadLocal应用场景
在通常的业务开发中,ThreadLocal 有以下3种典型的使用场景:
1.解决线程安全问题
ThreadLocal 用作保存每个线程独享的对象,为每个线程都创建一个副本,这样每个线程都可以修改自己所拥有的副本, 而不会影响其他线程的副本,确保了线程安全。
2.代替参数的显式传递
当我们在写API接口的时候,通常Controller层会接受来自前端的入参。
当这个接口功能比较复杂的时候,通常情况下,我们会在每个调用的方法上加上需要传递的参数。
但是,如果我们将参数存入ThreadLocal中,那么就不用显式的传递参数了,而是只需要ThreadLocal中获取即可。
这是因为:使用参数传递造成代码的耦合度高,使用静态全局变量在多线程环境下不安全,当该对象用ThreadLocal包装过后,就可以保证在该线程中独此一份,同时和其他线程隔离。
比如:在Spring的@Transaction事务声明的注解中,就使用ThreadLocal保存了当前的Connection对象,避免在本次调用的不同方法中使用不同的Connection对象。
3.全局存储用户信息
可以尝试使用ThreadLocal替代Session的使用,每个线程拥有独立的 Session 对象。
当用户要访问需要授权的接口的时候,可以现在拦截器中将用户的Token存入ThreadLocal中,之后在本次访问中任何需要用户用户信息的都可以直接冲ThreadLocal中拿取数据。
猜你喜欢
- 2025-01-23 Python闭包|你应该知道的常见用例(上)
- 2025-01-23 如何对配电柜局部放电情况进行有效监测及分析?
- 2025-01-23 Python闭包|你应该知道的常见用例(下)
- 2025-01-23 室内装饰设计施工图(室内装饰设计施工图设计阶段要做什么)
- 2025-01-23 Python启航:30天编程速成之旅(第12天)- 类
- 2025-01-23 张一飞:人类走到了全球战略文化的“十字路口”
- 2025-01-23 对话腾讯集团副总裁李强:大模型日趋理性,生态应用需要伙伴来实现
- 2025-01-23 急性阴道炎阴道瘙痒怎么办(霉菌性阴道炎反复发作怎么办)
- 2025-01-23 闭包,一个非常实用但容易被忽视的宝藏Python知识点
- 2025-01-23 JDK 17 本地变量类型推断的深度解析与应用场景
你 发表评论:
欢迎- 07-10动漫人物像|插画 壁纸 头像 签名 素材
- 07-10运动人物|插画 壁纸 头像 签名 素材
- 07-10动漫人物|插画 壁纸 头像 签名 素材
- 07-10神话人物|插画 壁纸 头像 签名 素材
- 07-10日漫人物像|插画 壁纸 头像 签名 素材
- 07-10 日漫人物|插画 壁纸 头像 签名 素材
- 07-10日漫人物风|插画 壁纸 头像 签名 素材
- 07-10日漫人物|插画 壁纸 头像 签名 素材
- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)