当前位置:网站首页>ThreadLocal线程变量
ThreadLocal线程变量
2022-06-29 07:40:00 【羡羡ˇ】
目录
ThreadLocal是什么?
ThreadLocal 使得我们可以创建线程私有的变量, 这个变量相对于其他线程来说是不可见的,ThreadLocal为变量在每个线程中都创建了一个副本 , 每个线程可以访问自己私有的线程变量,代码示例如下 :
public class ThreadLocalDemo {
//创建一个ThreadLocal对象,用来为每个线程会复制保存一份变量,实现线程封闭
private static ThreadLocal<Integer> localNum = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 1;
}
};
public static void main(String[] args) {
//线程0
new Thread(){
@Override
public void run() {
localNum.set(1);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
localNum.set(localNum.get()+10);
System.out.println(Thread.currentThread().getName()+":"+localNum.get());//11
}
}.start();
//线程1
new Thread(){
@Override
public void run() {
localNum.set(3);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
localNum.set(localNum.get()+20);
System.out.println(Thread.currentThread().getName()+":"+localNum.get());//23
}
}.start();
System.out.println(Thread.currentThread().getName()+":"+localNum.get());//0
}
}
如上所述, 算上main线程与新建的两个线程 ,总共三个线程 , 每个线程都包含自己的私有变量,此处我们设置值1 , set() 和 get() 方法用来设置值和获得值, 执行结果如下 :

ThreadLocal实现原理分析
ThreadLocal是一个泛型类 , 可以接受任何类型的对象 , 其内部维护了一个ThreadLocalMap 的静态内部类, 我们使用的 get(), set()等其实都来自这个类, 每次都会为当前线程创建一个ThreadLocalMap对象, 用来记录私有的值

先看 set() 方法
public void set(T value) {
//拿到当前线程
Thread t = Thread.currentThread();
//拿到当前线程map
ThreadLocalMap map = getMap(t);
if (map != null)
//存在设置值
map.set(this, value);
else
//不存在则创建
createMap(t, value);
}void createMap(Thread t, T firstValue) {
//threadLocals属性即为此map
t.threadLocals = new ThreadLocalMap(this, firstValue);
}接着是get() 方法
public T get() {
//拿到当前线程
Thread t = Thread.currentThread();
//拿到当前线程对应的map
ThreadLocalMap map = getMap(t);
//如果已有map
if (map != null) {
//取值操作, 拿到对应的Entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//没有map, 则去创建初始化一个map
return setInitialValue();
}private T setInitialValue() {
//initialValue()方法返回的value为null
T value = initialValue();
//拿到当前线程去创建对应的map
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}ThreadLocal可以理解为对ThreadLocalMap的封装
ThreadLocal内存泄漏问题
在ThreadLocalMap中 , 使用 ThreadLocal 的弱引用作为 key

这样的话, 如果一个ThreadLocal不存在外部强引用时, 那么key注定要被GC回收 , 这样导致ThreadLocalMap 中key为null , 而value还存在着强引用链
一个线程可以同时拥有多个ThreadLocal, 如果作为弱引用的key被回收后, value还不能被回收,那么这就导致此ThreadLocal的生命周期和此线程是一样长的(因为线程执行完毕后此value的强引用链才会断), 如果线程一直不结束, 堆积的value也一直无法被回收, 那么就会产生内存泄漏问题
这里解决问题的方式是 : 每次使用完ThreadLocal后都调用它的remove()方法清除数据
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}这里我们再来看一下key作为强弱引用的区别
如果key作为强引用, 那么它的生命周期和线程一样长,存在稳定的强引用链,无法被回收,产生内存泄漏问题, 而如果作为弱引用, GC则会自动的去回收它们, 在后续的remove()方法中也可以更好的去回收value , 所以我们一般将ThreadLocal设计成 private static 的, 在使用完后用remove()方法去手动删除它们
边栏推荐
- solidity部署和验证代理合约
- Audio and video development cases 99 lectures - Contents
- 802.11--802.11n协议 PHY
- 壁纸小程序源码双端微信抖音小程序
- À propos de Hook
- U盘内存卡数据丢失怎么恢复,这样操作也可以
- 笔记本电脑快速连接手机热点的方法
- MySQL system keyword summary (official website)
- Sonic communication - streaming data processing - window alignment
- Message Oriented Middleware: pulsar
猜你喜欢
![[hcie TAC] question 5-2](/img/a5/308aa2cced4cba59354c576a07e3c0.jpg)
[hcie TAC] question 5-2

Message Oriented Middleware: pulsar

Swift中@dynamicMemberLookup和callAsFunction特性实现对象透明代理功能

sql语句concat搜索不出结果

Debugging nocturnal simulator with ADB command

征文投稿丨使用轻量应用服务器搭建博客环境
![[Kerberos] analysis of Kerberos authentication](/img/c5/d429bcf3c26d9476531362ef286734.png)
[Kerberos] analysis of Kerberos authentication

Notice on organizing the second round of the Northwest Division (Shaanxi) of the 2021-2022 National Youth electronic information intelligent innovation competition

A review of visual SLAM methods for autonomous driving vehicles

Un voyage profond d'IA dans Huawei Cloud
随机推荐
What are the organizational structure and job responsibilities of product managers in Internet companies?
1284_ Implementation analysis of FreeRTOS task priority acquisition
Program debugging - debug/release version
Un voyage profond d'IA dans Huawei Cloud
Stm32 usart+dma usage based on Hal Library
Product security - small vulnerabilities cause big problems
关于SQL语句的大小写
Improvement direction of programming ability
Flutter file read / write -path_ provider
In PHP version 7.1.13, it is found that floating-point data passes through JSON during use_ There will be precision problems after encode
Flutter shared_ Preferences use
Basics - syntax standards (ANSI C, ISO C, GNU C)
Linear regression with one variable
[eye of depth wuenda machine learning homework class phase IV] regularization regularization summary
Soliciting articles and contributions - building a blog environment with a lightweight application server
Blueprint basis
Reflection perfectionism
dcase_ Util tutorial
关于#sql#的问题:创建一个名为View_XB视图,功能是①如果有重名的视图先删除后创建②显示XSB表中本班级的男女生各有多少人,并添加检查约束
微信小程序开发,如何添加多个空格