ThreadLocal ThreadLocal是一个用于实现线程数据隔离的一个类,每个线程访问时,通过Get、Set方法都会产生一个属于该线程的局部变量副本,当线程结束时,ThreadLocal及变量随着线程一起被回收。 Threa
ThreadLocal是一个用于实现线程数据隔离的一个类,每个线程访问时,通过Get、Set方法都会产生一个属于该线程的局部变量副本,当线程结束时,ThreadLocal及变量随着线程一起被回收。
总的来说,ThreadLocal有三大用途:
1. 保存线程上下文信息,在任何地方都可以获取(通过static关键字) 我们可以使用static关键字,在任意地方都可以对该ThreadLocal进行获取、设置。 例如spring中的事务,用ThreadLocal存储了连接对象,保证一次事务的所有操作都在同一连接上。 2. 线程安全,避免某些情况下需要保持同步而带来的性能损失 3. 线程之间数据隔离
ThreadLocal虽然叫线程局部变量,但是它不存储任何数据,它只是一个壳子,真正的存储结构是在ThreadLocal中有一个ThreadLocalMap的一个内部类,而这个内部类却被Thread定义为了成员变量。
而ThreadLocal本身并不存储值,它只是作为key存储在Thread对象中的ThreadLocalMap中,而value则是我们存储的变量。
那么,既然真正存储数据的是Thread对象中的ThreadLocalMap,每个线程都是自己的Thread对象,那么也就达成了线程私有变量以及数据隔离。
public void set(T value) { // 返回当前 ThreadLocal 所在的线程 Thread t = Thread.currentThread(); // 返回当前线程持有的map ThreadLocalMap map = getMap(t); if (map != null) { // 如果 ThreadLocalMap 不为空,则直接存储键值对 map.set(this, value); } else { // 否则,需要为当前线程初始化 ThreadLocalMap,并存储键值对 createMap(t, value); }}
主要有几个步骤:
- 获取当前线程
- 将当前线程传入getMap()方法,获取ThreadLocalMap对象
- 设置 key 为 [当前ThreadLocal对象],value为我们设定的值。
- 如果Map不存在,则创建一个Map
这时候,我们肯定纠结,这个Map到底是什么?我们接着看:
进入getMap() 方法:
这是我们可以看到,该方法返回了当前线程的 threadLocals 属性,那我们再看看是什么:
原来是在Thread对象中,看到这里是不是有种明悟,原来:
ThreadLocalMap map = getMap(t))
map.set(this, value)
createMap(t, value);void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);}
我们都知道,每个线程在Java内部都表现为一个Thread对象,而每个Thread对象都拥有 threadLocals 属性,在线程调用了 set() 方法后,会初始化该属性,并且将本线程所属的元素存入进去,这样就造成了数据隔离,每个线程有自己的数据。
实战验证:
我们都知道,SimpleDateFORMat因为内部使用了日历对象Calendar,导致不能将其作为线程共享对象,会引发线程安全问题。
(因为只有一个Calendar实例,而多线程共享该实例 )
结果(线程1及线程2运行时设置的时间被线程3覆盖,导致出现了错误的结果):
结果(因为每个线程都存着自己的那份SimpleDateFormat对象,所以不会出现并发情况):
Debug:
线程1拥有的:
线程2拥有的:
线程3拥有的:
可以看到,每个线程都拥有自己的SimpleDateFormat对象。
ThreadLocal内存泄漏指的是:ThreadLocal对象被回收了,但是线程内的ThreadLocalMap成员与线程一样继续存在着,它不会回收,就出现了一个现象,就是ThreadLocalMap的key没了,Map没有了指向,但value还在,key的引用一直在就造成了内存泄漏。
而为什么ThreadLocal对象会被回收呢,因为它是弱引用。它的生命周期更短,会在一次GC后回收掉。
所以使用其最好的方式是:用完了,将其remove掉,从Thread.threadLocals(Map)中删除即可。
总的来说,ThreadLocal通过避免并发保证数据安全,将数据绑定到Thread对象上,保证了数据隔离。而在使用完毕后,必须手动将值进行remove(),否则,当线程一直运行时,容易出现内存泄漏风险。
来源地址:https://blog.csdn.net/qq_44316957/article/details/127301227
--结束END--
本文标题: 【ThreadLocal详解】
本文链接: https://lsjlt.com/news/375263.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-04-01
2024-04-03
2024-04-03
2024-01-21
2024-01-21
2024-01-21
2024-01-21
2023-12-23
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0