首页 > 其他分享 >不规范使用ThreadLocal导致的bug,说多了都是泪

不规范使用ThreadLocal导致的bug,说多了都是泪

时间:2023-01-11 17:08:27浏览次数:39  
标签:String after ThreadLocal 规范 threadLocal 线程 bug before

ThreadLocal一般用于线程间的数据隔离,通过将数据缓存在ThreadLocal中,可以极大的提升性能。但是,如果错误的使用Threadlocal,可能会引起不可预期的bug,以及造成内存泄露。

因为线程重用导致的信息错乱的bug

有时我们会在一个接口中缓存某些数据到ThreadLocal中,但是我们要意识到,处理请求的这些线程是由tomcat提供的,而tomcat提供的线程都是配置在一个线程池中的。

也就是说,线程是可能被重用的,如果线程一旦被重用,而ThreadLocal的数据没有及时重置,就会导致数据被混乱使用。

以下方的接口为例,先获取当前线程中保存的数据信息,将参数中的name保存到ThreadLocal中以后,再获取一次。

@GetMapping(value = "/threadLocal")
public ResponseEntity<Object> threadLocal(String name) {
String before = Thread.currentThread().getName() + ":" + threadLocal.get();
//先获取值,理论上应该是null
System.out.println("before:" + before);
threadLocal.set(name);
String after = Thread.currentThread().getName() + ":" + threadLocal.get();
//设置完参数值再获取一次
System.out.println("after:" + after);
return ResponseEntity.ok().build();
}
复制代码

为了尽快复现线程重用导致的问题,我们将servlet.tomcat.threads.max设置为1,这样每次请求使用的都是同一个线程。

不规范使用ThreadLocal导致的bug,说多了都是泪_数据

第一次请求接口,数据看起来很正常:

不规范使用ThreadLocal导致的bug,说多了都是泪_线程池_02

但是第二次请求接口时,可以看到线程仍然是http-nio-8080-exec-1,但是before却打印出了第一次请求的参数test。

不规范使用ThreadLocal导致的bug,说多了都是泪_tomcat_03

这就是因为没有及时重置ThreadLocal导致的数据错误。

正确使用的姿势

修正的办法就是处理完接口之后要及时清理ThreadLocal。

@GetMapping(value = "/threadLocal")
public ResponseEntity<Object> threadLocal(String name) {
try {
String before = Thread.currentThread().getName() + ":" + threadLocal.get();
//先获取值,理论上应该是null
System.out.println("before:" + before);
threadLocal.set(name);
String after = Thread.currentThread().getName() + ":" + threadLocal.get();
//设置完参数值再获取一次
System.out.println("after:" + after);
} finally {
//清理数据
threadLocal.remove();
}
return ResponseEntity.ok().build();
}
复制代码

更优雅的处理方式

可能也有的朋友会说,每次都要使用try finally处理线程数据,未免也太麻烦了。其实,我们可以使用拦截器或者过滤器自动帮我们完成数据的初始化以及清理工作。

不规范使用ThreadLocal导致的bug,说多了都是泪_tomcat_04

最后

我们在写业务代码时,正确的理解线程的全生命周期以及执行原理,对我们提升代码的健壮性其实很有帮助。有时我们觉得底层原理很枯燥乏味,开发业务就是写增删改查,多线程用的也很少,但我们只是没有意识到,我们的代码一直跑在tomcat提供的线程池中,本身就是一个多线程的环境。

除了tomcat的线程池,我们自定义的线程池其实也会有这个问题,大家可以看看自己的业务代码是否踩过这个坑。


标签:String,after,ThreadLocal,规范,threadLocal,线程,bug,before
From: https://blog.51cto.com/u_15462217/6002345

相关文章

  • react-native启动时报错Execution failed for task ':app:checkDebugAarMetadata'
    报错内容如下:FAILURE:Buildfailedwithanexception.*Whatwentwrong:Executionfailedfortask':app:checkDebugAarMetadata'.>Multipletaskactionfailur......
  • react-native启动时报错Could not determine the dependencies of task ':app:preDebu
    报错如下:需要修改node_module中的@react-native-community/viewpager文件,如下:再次启动即可。......
  • API规范文档
    URI命名规范URI应全部小写,多个字母之间用横杆`-`分割,比如:/dts-admin/job-info/alarm-email-groupsURI用于表示资源,所以URI应该用名词表示,动作表示应该通过GET,POST......
  • 菜鸡的bug-前端开发的get请求携带对象参数的问题
    我们开发的过程中,一般都是将axios封装后,简单的设置一下基地址、请求时间、请求拦截器中的请求头,响应拦截器中对能连通的接口的错误抛出处理、响应返回的数据的剥离处理等。......
  • 菜鸡的bug-vue组件中传递的数据能显示,但是控制台报not defind的错误
    在vue开发的父子组件传值的时候,我们一般都是先封装一个子组件,给他取名字,然后在要用到此组件的页面,也就是所说的父组件中将这个子组件导入、注册、再使用。我们一般都是用驼......
  • 菜鸡的bug-vue父子传值props的报错
    我们在vue中通过props来进行父子传值的时候,在当前页面没有问题,但是切换到其他页面的时候控制台会报错。后来我们会发现在props中简单的接受单个属性的时候没什么问题,但是......
  • ThreadLocal底层原理
    文章目录1.什么是ThreadLocal?2.ThreadLocal基本用法3.ThreadLocal的应用场景4.ThreadLocal底层原理5.强软弱引用之间的区别5.1强引用5.2软引用5.3弱引用5.4虚引用6.Thr......
  • html书写规范
    标签换行写法<div><p>今天的天<span>真的好啊</span></p></div>CopytoclipboardErrorCopied 标签需要关闭<p><span>哈哈哈哈......
  • ThreadLocal源码解析
    一、ThreadLocal概述ThreadLocal是一个线程的本地变量,也就意味着这个变量是线程独有的,是不能与其他线程共享的。这样就可以避免资源竞争带来的多线程的问题。但是,这种解......
  • 线程数据共享与安全-ThreadLocal
    1.ThreadLocal作用在一个线程中,线程安全的共享数据(实现在同一个线程中共享数据,从而解决多线程数据安全的问题)分析:1.数据:可以是普通变量,对象,数组等。(在一个线程中)一个数据......