当前位置:网站首页>工作积累——Web请求中使用ThreadLocal遇见的问题
工作积累——Web请求中使用ThreadLocal遇见的问题
2022-06-26 05:59:00 【大·风】
发现错误
在我们实现业务的时候会将一些仅用于当前线程的数据使用
ThreadLocal保存起来,在业务执行的某个时机将其取出来,因为线程隔离的特性让我们不必担心其他线程访问到错误的数据。
最近遇见一个BUG,相同的业务在请求中获取到了不同的返回结果。后来发现是`ThreadLocal``引起的问题。
ThreadLocal数据被共享?
ThreadLocal的数据是线程隔离的这个很多人都介绍过了,随着线程销毁,数据也会销毁。那么不同的请求能访问到其他请求中的数据有一个原因可能是ThreadLocal中的数据使用完后未被销毁,而线程被重用了。这个场景可以使用线程池模拟。
下面代码中模拟向ThreadLocal中设置参数,线程池会重用固定的几个线程,一旦线程重用ThreadLocal 中数据如果没被清空则会出现新的任务读取到旧数据
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(2,2,0, TimeUnit.SECONDS,new LinkedBlockingDeque<>(12));
List<Runnable> runList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
runList.add(() -> {
System.out.println("当前线程:" + Thread.currentThread().getName());
String value = threadLocal.get();
if (value == null) {
threadLocal.set(Thread.currentThread().getName());
System.out.println("threadLocal 不存在数据,设置参数 :" + Thread.currentThread().getName());
} else {
System.out.println("threadLocal 已经存在数据,参数 :" + value);
}
});
}
runList.forEach(executorService::execute);
executorService.shutdown();
}
在输出的结果中可以看到后面几条任务已经出现错误,读取到了之前线程的数据
当前线程:pool-1-thread-1
当前线程:pool-1-thread-2
threadLocal 不存在数据,设置参数 :pool-1-thread-1
threadLocal 不存在数据,设置参数 :pool-1-thread-2
当前线程:pool-1-thread-1
threadLocal 已经存在数据,参数 :pool-1-thread-1
当前线程:pool-1-thread-2
threadLocal 已经存在数据,参数 :pool-1-thread-2
当前线程:pool-1-thread-1
threadLocal 已经存在数据,参数 :pool-1-thread-1
Tomcat的工作线程
上面的例子中可以发现,存在线程重用的场景下时ThreadLocal的数据如果没有及时清理会导致重用此线程的业务读取错误的数据。而
Tomcat在执行请求的工作线程就是从线程池中获取的,在官方文档中关于线程池的配置https://tomcat.apache.org/tomcat-8.5-doc/config/executor.html#Standard_Implementation的文章中指明了默认的线程池org.apache.catalina.core.StandardThreadExecutor。
通过分析初始化的方法和里面的逻辑可以发现,StandardThreadExecutor的实现本质上通过ThreadPoolExecutor实现业务的。
@Override
protected void startInternal() throws LifecycleException {
taskqueue = new TaskQueue(maxQueueSize);
TaskThreadFactory tf = new TaskThreadFactory(namePrefix,daemon,getThreadPriority());
executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf);
executor.setThreadRenewalDelay(threadRenewalDelay);
if (prestartminSpareThreads) {
executor.prestartAllCoreThreads();
}
taskqueue.setParent(executor);
setState(LifecycleState.STARTING);
}
需要注意的是:Tomcat的线程池的名字也叫作ThreadPoolExecutor,是继承了JDK的ThreadPoolExecutor然后进行了一些逻辑封装。
Tomcat的线程队列保存在org.apache.tomcat.util.threads.TaskQueue中就是上面这段代码taskqueue = new TaskQueue(maxQueueSize)。
可以看到Tomcat为了提供处理请求的效率也是使用线程池来处理请求的,这意味的线程会被重用,这样在使用一些线程变量的时候,如果在任务结束后没有主动请求这些数据,这些数据就会污染线程导致后续业务错误。
ThreadLocal产生的问题却不是ThreadLocal的问题
ThreadLocal作为一个可以设置线程共用数据的工具,能实现很多业务。很多时候我们在实现某些逻辑的时候没有意识到这些逻辑一直运行在一个多线程环境。用好ThreadLocal,不仅要理解ThreadLocal也要理解运行ThreadLocal的环境。有时ThreadLocal的问题却不是ThreadLocal产生的问题
边栏推荐
- The most refined language interprets the event dispatcher (also known as the event scheduler)
- Getting started with Python
- 卷妹带你学jdbc---2天冲刺Day2
- [intra group questions semester summary] some reference questions for beginners
- 小程序第三方微信授权登录的实现
- 04. basic data type - list, tuple
- Func < T, tresult > Commission - learning record
- Implement the runnable interface
- volatile应用场景
- 【C語言】深度剖析數據在內存中的存儲
猜你喜欢

Solve the problem that Cmdr cannot use find command under win10

Factory method pattern, abstract factory pattern

Younger sister Juan takes you to learn JDBC -- two days' Sprint Day2

小程序如何关联微信小程序二维码,实现二码聚合

Prototype mode, Baa Baa

怎么把平板作为电脑的第二扩展屏幕

Redis multithreading and ACL

家庭记账程序(第一版)

MySQL-07

Mysql-10 (key)
随机推荐
MySQL-05
从新东方直播来探究下小程序音视频通话及互动直播
5 minutes to learn regular expressions
Pytorch (environment, tensorboard, transforms, torchvision, dataloader)
Gram 矩阵
About abstact and virtual
重载和重写
Machine learning 05: nonlinear support vector machines
pytorch(环境、tensorboard、transforms、torchvision、dataloader)
Detailed explanation of serial port communication principle 232, 422, 485
numpy. frombuffer()
Sql语法中循环的使用
Implementation of third-party wechat authorized login for applet
状态模式,身随心变
Pytorch (network model training)
Last flight
Household accounting procedures (First Edition)
Consul service registration and discovery
String class learning
Definition of Halcon hand eye calibration