当前位置:网站首页>ThreadLocal遇到线程池出现数据问题和解决方案
ThreadLocal遇到线程池出现数据问题和解决方案
2022-07-22 10:44:00 【程序猿洞晓】
ThreadLocal开发中常用,通过ThreadLocal操作数据实现线程之间的隔离,保证线程之间不会因为操作同一数据导致数据安全问题。但是这种隔离是有适用范围的,也就是说在某些特定的情况下还是会出现数据安全问题的。这种特定情况下就是使用到线程池,并且在ThreadLocal使用前后没有做数据清理,就会导致安全问题,下面来看看出现的情况和具体怎么去解决。
ThreadLocal正常使用
一个main方法的主线程,再创建一个新的线程作为模拟线程,同时操作ThreadLocal,通过在打印对应的输出值来看ThreadLocal的作用。
public class ThreadLocalDemo {
private static ThreadLocal<Integer> local = new ThreadLocal<>();
public static void main(String[] args) {
local.set(1);
System.out.println(Thread.currentThread().getName() + "===>" + local.get());
operateLocal();
//模拟另一个线程
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "===>" + local.get());
local.set(4);
System.out.println(Thread.currentThread().getName() + "===>" + local.get());
operateLocal();
}).start();
}
private static void operateLocal() {
Integer value = local.get();
local.set(++value);
System.out.println(Thread.currentThread().getName() + "===>" + local.get());
}
}
输出的结果:
main===>1
main===>2
Thread-0===>null
Thread-0===>4
Thread-0===>5
从结果就可以知道,两个线程之间没有互相的干扰,各自操作各自空间里面的数据,达到了线程安全的特性。这个也是正常使用所用到的。单对于这种方式来说是线程安全的,数据也是安全的,但是下面看看会出现问题的场景。
线程池下的ThreadLocal
这里创建一个线程池,为了模拟方便,线程池里面只创建一个线程,然后通过ExecutorService
两次来对ThreadLocal进行操作,你会发现一个问题。
public class ThreadLocalDemo {
private static ThreadLocal<Integer> local = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();//线程池
executorService.execute(() -> {
//1
local.set(123);
System.out.println(Thread.currentThread().getName() + "==>" + local.get());
});
executorService.execute(() ->//2
System.out.println(Thread.currentThread().getName() + "==>" + local.get())
);
executorService.shutdown();
}
}
在代码块1向ThreadLocal里面添加值为123,然后打印出来对应的线程名称和ThreadLocal里面存储的值。然后在代码块2里面从ThreadLocal里面获取值。输出的结果如下:
pool-1-thread-1==>123
pool-1-thread-1==>123
两个位置输出的内容相同,也就意味着当使用线程池的时候,一个线程设置的数据可能残留在ThreadLocal里面,等下一个线程使用的时候可能直接拿到之前操作残留的数据,导致数据的污染问题。
在这里需要了解的是,在很多博客里面(当然包含我转载的一些博客)都说ThreadLocal里面的ThreadLocalMap的键是弱连接,当下一次GC回收的时候会自动回收,不会出现数据的安全问题。但是这种说法是有特定场景的,也就是说当前线程执行结束后,ThreadLocal对象需要被手动的置为null。因为GC不是时刻去执行的,是需要达到一定的条件,所以存在滞后。
在使用ThreadLocal的时候为了线程安全,基本都是放在成员变量里面,每次执行结束置为null的操作稍微不注意就不会去做,或者漏掉,这样带来的另一个麻烦就是每次使用的时候还要new创建一个ThreadLocal,总感觉很别扭。
总结一下:
- GC执行需要条件不可能在当前线程执行结束立即执行,清理掉ThreadLocal里面存储的数据
- 即使GC触发,在ThreadLocal被外部的成员变量建立了强连接,是一样清理不掉的
- 每次执行结束将null赋值给成员变量,在执行开始的时候,手动初始化ThreadLocal
提出的解决方法
线程池和ThreadLocal不同时用
这个好像有点扯,线程池在正常的一个java项目中都会被用到,换句话说就是放弃ThreadLocal不用啦。所以这种解决方案过于极端。
清理ThreadLocal数据
这个是我个人目前想到的最好的方法了,可以使用面向切面的思想,切入到使用ThreadLocal的方法,在方法执行前、执行结束后、抛出异常时对ThreadLocal进行数据清理动作。
示例代码:
public static void main(String[] args) {
local.remove();//清理
try {
//……
} catch (Exception e) {
//……
} finally {
local.remove();//清理
}
}
只是demo示例,没有具体的业务内容,也没有根据切面来具体实现,偷懒了一把,只提供思路。
总结
在使用ThreadLocal的时候还是要很注意的,虽然在ThreadLocal里面已经用弱连接这种机制和GC对弱连接的回收方式来实现及时的数据回收,在实际的开发中,还是存在一些问题的,所以不能完全依靠于ThreadLocal,还是要多方面的思考,做到严谨性。这个问题之前我也没有想到,在业务代码中使用到,结果是同事看到我的代码提醒我的(论有一群好的战友的重要性)。
边栏推荐
- 结构体和联合体
- Wiring ability of twisted common centroid capacitor array under signal coupling constraints
- 1045 favorite color stripe (30 points)
- Configure your own VIM editor God
- 模拟电路中晶体管阵列的性能感知公共质心布局和布线 ALIGN
- 1045 Favorite Color Stripe (30 分)
- 适用于高密度或高精度应用的高度可配置和可扩展的螺旋电容器设计
- Pytorch不同层设置不同学习率
- 尾插法构造链表
- Intensive reading of Detr paper and analysis of model structure
猜你喜欢
【FPGA】:ip核---乘法器(multiplier)
Wiring ability of twisted common centroid capacitor array under signal coupling constraints
【文献阅读与想法笔记14】Beyond a Gaussian Denoiser: Residual Learning of Deep CNN for Image Denoising
【keil软件】仿真时如何使用逻辑分析仪查看波形
【fpga】gtx/gth概述
Airtest 进行WebUI自动化测试(selenium)
Canny edge detection
测试相关基础概念
Configure your own VIM editor God
[literature reading and thought notes 14] beyond a Gaussian noise: residual learning of deep CNN for image recognition
随机推荐
1076 forwards on Weibo (30 points)
ADB自动化测试框架
APP专项测试
PASTEL:电荷再分配 SAR-ADC 中具有广义比率的电容器阵列的寄生匹配驱动布局和布线
Wiring ability of twisted common centroid capacitor array under signal coupling constraints
7-3 size of military unit (25 points)
Performance perception of transistor arrays in analog circuits common centroid layout and wiring align
Pytoch realizes the fixation of some layers of the network without updating the loopback
Simulated student information input interface
【FPGA】:MicroBlaze的使用
pytest测试框架快速搭建
【FPGA】:ip核--Divider(除法器)
locust测试框架快速搭建
VIM configuration
使用多种加权方法在 SAR ADC 中放置二进制加权电容阵列
Canny edge detection
【面试:基础篇05:快速排序】
类的属性新建(初级理解)
顺序表的创建插入和修改
7-2 rank a linked list (25 points)