多线程中ThreadLocal踩坑

ThreadLocal存List遇到的坑 背景 项目有个需求,存储一个类成员变量。供类中的各个方法使用,是在easyexcel 中 最一开始没有注意到service是单例模式的,所以每回存取requiredColIndexs的需要验证的列索引有可能是上一个模版的。 后来加了threadlocal后,发现还是有异常。 @Slf4j public class TemplateExcelListener extends AnalysisEventListener<Map<Integer, String>> { 阅读详情

前言

记录一下在测试过程中,遇到的一个有关ThreadLocal的问题,顺便学习一下ThreadLocal相关的知识。

ThreadLocal介绍

ThreadLocal是一个关于创建线程局部变量的类。

要点:
* 在当前线程中,任何一个地方都可以访问到ThreadLocal的值。
* 当前线程保存在ThreadLocal中的值只能被当前线程访问,一般情况下其他线程访问不到。
* ThreadLocal内部存储数据是以ThreadLocalMap(类似Map的key-value存储方式)来存储的,以当前线程为key,以需要存储的数据为value

问题场景

最近项目需要上线一个大版本,此次版本对前端APP新、老版本发起的请求做了不同的加密处理,经过讨论,需要在后台做版本兼容。

兼容的流程:

  • APP端在请求头里面新增一个字段作为新版本APP的标识,如:varA:123
  • 后端在SpringDispatcherServlet中判断varA是否为空,若不为空则把它放入ThreadLocal变量中

    if (StringUtil.isNotEmpty(varA)){
      ThreadContext.put(ThreadContext.FLAG, varA);
    }
  • 然后在JsonHttpMessageConverter(自定义请求解析类)中,根据varA是否为空来决定采取哪种解密方式来解密请求

    String flag = ThreadLocal.get(ThreadContext.FLAG);
    if (StringUtil.isNotEmpty(flag)){
      //新版本解密方式
    }else{
      //老版本解密方式
    }
  • 逻辑处理

  • 响应请求

问题描述

按照上面的兼容流程做完代码更改之后,在本地测试没有问题,但是放在测试环境,由测试人员测试就有问题。

具体问题描述:

  • 老版本APP发起的请求在后台解密时会进入新版本APP解密方式的判断里面去,但是只是部分请求才会出现此情况

分析结果

我们知道,后端应用服务器在处理请求时,会对每一个请求分配一个线程来处理,如果每次来一个请求都去新开一个线程,然后响应请求之后又去销毁线程,这样的结果不仅会增加请求响应时间,而且还会大大提高系统资源消耗。

所以为了适应高并发请求,在应用服务器端都会使用线程池来处理请求,效果是减少系统资源开销以及加快请求响应时间。

前面讲到,由于ThreadLocal是以当前线程为key,所以如果前后有两条请求发到后台,并且这两条请求都是使用的线程池里面的同一个线程。并且第一条是新版本APP发过来的带有标识的请求,第二条是老版本APP发过来的不带标识的请求。

第一条请求把标识存入ThreadLocal变量中,在响应完请求之后没有及时的清理掉ThreadLocal中的值

当第二条不带标识的请求到来时,由于在SpringDispatcherServlet中做了不为空才把标识放入ThreadLocal中,所以这里就没有更新ThreadLocal中的值,但其实由于前面一个请求响应之后没有清理掉ThreadLocal中的值,所以在JsonHttpMessageConverter中获取当前线程的标识时,还是有值,这样就会进入新版本的解密方式中去。

问题处理

两种方式:

  • 在SpringDispatcherServlet中不做判空处理,从请求中不管获取到什么值都存入ThreadLocal变量中,以此达到实时更新值的效果

  • 在响应完请求之后移除ThreadLocal中想要移除的值或清空ThreadLocal里面当前线程保存的所有值

ThreadContext.remove(ThreadContext.FLAG);
或者清空所有
ThreadContext.remove();

最后我采取的第二种方式,因为按逻辑是ThreadLocal里面的数据只适合在本次请求中使用,使用完了之后就得清理掉。

从零开始学习CANoe(三)—— 系统变量的创建和使用 阅读详情

相关推荐

Nginx健康检查实战:如何用第三方模块提升服务可用性(附详细配置)

本文深入探讨了如何通过集成第三方健康检查模块来提升Nginx的服务可用性。文章对比了Nginx默认被动检查的局限性,并详细介绍了主动健康检查的核心优势、主流模块选型,以及以nginx_upstream_check_module为例的实战部署与配置指南,帮助运维人员构建更可靠的负载均衡架构。

weixin_28331555的博客 308

解锁ThreadLocal的问题集:如何规避多线程中的坑

在多线程编程中,ThreadLocal被广泛应用于解决共享变量的问题,然而,它也不是银弹。本文深入探讨ThreadLocal存在的问题,揭示在使用它时可能遇到的陷阱和困扰,以及如何规避这些潜在风险。

todoitbo的博客 1万+

XGBoost与Embedding混合建模实战解析

在机器学习领域,特征工程与模型融合是提升预测性能的关键技术。Embedding技术通过将高维稀疏特征(如文本、ID类数据)转化为低维稠密向量,有效捕获语义关联;而XGBoost作为强大的集成学习算法,擅长处理结构化特征并进行自动特征组合。两者结合的混合架构(如Semantic Boosted Trees)在金融风控和推荐系统等场景中展现出显著优势,尤其在处理用户行为序列、商品ID等复杂特征时,相比传统方法能获得更好的模型效果。本文通过电商推荐和金融反欺诈等案例,详解如何实现Embedding+XGBoost

weixin_28718641的博客 325

ThreadLocal巨坑!内存泄露只是小儿科

本文将会详细总结 ThreadLocal 容易用错的三个坑:内存泄露线程池中线程上下文丢失并行流中线程上下文丢失内存泄露由于 ThreadLocal 的 key 是弱引用,因此如果使用后不调用 remove 清理的话会导致对应的 value 内存泄露。 当 localCache 的值被重置之后 cacheInstance 被 ThreadLocalMap 中的 value 引用,无法被 GC,但是其 key 对 ThreadLocal 实例的引用是一个弱引用。本来 ThreadLocal 的实例被 lo

hahazz233的博客 1031

MPU6050 加速度计和陀螺仪传感器与 Arduino 的接口

虽然该模型并不能准确代表现实世界中加速度计传感器的构建方式,但它通常有助于理解为什么加速度计的输出信号通常以 ±g 为单位指定,或者为什么加速度计在静止时在 z 轴上的读数为 1g,或者在不同方向上您可以期望得到什么样的加速度计读数。该模块的核心是低功耗、低成本的 6 轴运动跟踪芯片 MPU6050,它将 3 轴陀螺仪、3 轴加速度计和数字运动处理器 (DMP) 集成到一个 4mm x 4mm 的微型芯片中。小时候,科学博览会上的陀螺仪总是让我们感到惊讶,因为它们以奇怪的方式移动,甚至似乎违背了重力。

sxstj的博客 9932

手把手教你学Simulink--双足机器人分数阶PID控制仿真

分数阶PID(Fractional-order PID, FOPID)控制是一种先进的控制策略,它扩展了传统的整数阶PID控制器的概念。FOPID控制器允许积分和微分项的阶次不是严格的整数,而是可以是任意实数,这为系统提供了更多的设计自由度,并可能带来更好的性能。在双足机器人控制中,分数阶PID控制可以用于改善机器人的平衡控制、轨迹跟踪等任务的性能。下面我们将详细介绍如何使用Simulink进行基于分数阶PID控制方法的双足机器人仿真研究。

MHD0815的博客 880

那些年你踩过的InheritableThreadLocal的坑

`InheritableThreadLocal`在使用线程池的情况下通常会使用不当导致踩坑,线程上下文中的数据并不是期望的数据!

天的博客 3974

黑群晖DSM7.0.1物理机安装教程

使用芯片无忧工具,查看U盘的和。使用,格式化U盘。使用镜像写入工具,把引导写入U盘。修改文件,可以使用工具把文件复制到桌面,通过修改好之后,拖进这个界面中。或者在电脑中,查看U盘,打开U盘中的文件直接修改。具体修改内容如下:PID修改为U盘的PIDVID修改为U盘的VID默认只有mac1=a8412083CB52 mac2=0a11323D47F7 ,增加:mac3=a15823C08000 mac4=a23C04158B52 mac5=82a002524158 mac6=38233052415aS

JingLisen的博客 2万+

使用ThreadLocal遇到的坑

前提:在SpringBoot 中使用ThreadLocal存储上下文信息,方便信息在不同类之间方便传递,用户信息错乱。 ThreadLocal 应用场景举例: SpringSecurity 存储当前登录的用户信息–> SecurityContextHolder Spring 中事务处理,保证多个Service公用一个连接才能保证事务的一致性,会把Connection信息存储在ThreadLocal中 问题解决方案: ThreadLocal 在线程销毁的时候会回收里面的值,但是如果线程归还给线程池,

小左的博客 1901

【微服务】SpringBoot 整合Kafka 项目实战操作详解

SpringBoot 整合Kafka 实战操作详解

congge 5570

手把手完整实现STM32+ESP8266+MQTT+阿里云服务器+手机APP应用——第一节—阿里云物联网平台配置+IoTStudio界面绘制+MQTT.fx模拟MQTT客户端与使用AT命令发布订阅消息

通过MQTT.fx模拟连接以及通过CH340串口连接ESP8266发送AT命令,实现阿里云物联网平台发送数据同时接收数据,IOT studio界面显示数据。具体来说:使用ESP8266(本系列使用了ESP8266-ESP01/01S以及正点原子的ATK-ESP8266) 来连接网络,获取设备数据发送到阿里云物联网平台并显示数据,通过IOT studio界面显示数据并发送命令控制设备。本系列使用的主控芯片是STM32F103系列,当然也可以使用其他系列单片机都可以实现,思路都是一样的。同时本系列有手机APP源

嵌入式阿齐Archie 5万+

ThreadLocal 使用和详解避坑

线程栈用于存储方法调用的信息,而线程本地存储则是每个线程私有的存储空间,用于存储线程的局部变量。ThreadLocal类提供了一种简单的方式来实现线程本地存储,它允许将线程特定的值与每个线程关联起来。线程池中的线程重用:在使用线程池的情况下,线程会被重用。如果线程在使用ThreadLocal之后没有进行清理操作,可能会导致后续使用该线程时,获取到之前线程的ThreadLocal变量值。通过将对象存储在ThreadLocal变量中,可以保证每个线程都有自己的私有对象,从而避免竞争条件的发生。

DS_Watson的博客 623

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

多线程环境下ThreadLocal引发的隐藏安全漏洞,90%开发者都踩过坑!

通过Filter强制清理 + 防御性编程 + 自动化测试的三重保障,我们彻底解决了用户数据“穿越”问题。技术细节决定系统安危,一个小小的使用不当,竟可能引发严重安全事故!

2401_89221867的博客 468

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

ThreadLocal 可能踩到的坑

背景 首先ThreadLocal 不做太多的介绍,在多线程场景下有着广泛的应用。 最近在实现OneLog方法级日志的时候,使用了 ThreadLocal 作为缓存和计数器,在调试过程中,发现有一些场景会出现数据错乱和内存溢出的问题。 详情 OneLog方法级日志使用 ThreadLocal 有两个场景,一个是将方法入参信息缓存起来,然后在方法结束之...

weixin_34122604的博客 584

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

七年老码农掏心窝:你踩过的 ThreadLocal 坑,我替你填了 3 遍

刚听到 ThreadLocal 时,我脑补的是 "每个线程自带一个 Local 变量",后来发现差不多就这意思!打个比方:假设你和室友合租,共用一个杯子(共享变量),结果他喝完没洗,你喝的时候就得先刷杯子(加锁)。但如果每人发一个专属杯子(ThreadLocal),各用各的,再也不用抢了 ——ThreadLocal 就是让每个线程拥有自己的变量副本,互不干扰

Minoz_wl的博客 1538

ThreadLocal线程缓存踩坑笔记

看一场戏,听一场雨,真是有趣。 主角之一:ThreadLocal线程缓存Context上下文 ThreadLocal<SomeContext> someContext = new ThreadLocal<>(); String someToken = someContext.getToken(); String someAccountNo = someContext.g...

来啦,老弟~ 1040

ThreadLocal原理、ThreadLocal的使用、ThreadLocal内存泄漏、ThreadLocal的坑

文章目录背景说明一:ThreadLocal的原理1.1 什么是ThreadLocal变量1.2 ThreadLocal实现原理1.3 ThreadLocalMap实现原理1.4 ThreadLocalMap结构图二:ThreadLocal的使用2.1 创建ThreadLocal工具类2.2 在拦截器/过滤器中通过用户token获取登录信息,并与当前线程绑定2.3 业务处理时获取用户信息2.4 当前请求结束时,销毁ThreadLocal变量三:ThreadLocal的坑、ThreadLocal内存泄漏3.1

weixin_49114503的博客 8910

多线程-ThreadLocal

ThreadLocal提供线程局部变量。这些变量与正常的变量不同,因为每一个线程在访问ThreadLocal实例的时候(通过其get或set方法)都有自己的、独立初始化的变量副本。ThreadLocal实例通常是类中的私有静态字段,使用它的目的是希望将状态(例如,用户ID或事务ID)与线程关联起来。

存在,即合理 1315

在踩坑中深入理解ThreadLocal

简介 ThreadLocal 是一创建线程局部变量的类,就是说这个类创建的变量值能被当前线程访问,其他线程无法访问和修改。 特点 Global:在当前线程中,任何位置能获取到ThreadLocal的值 Local:该线程的ThreadLocal只能被该线程访问,一般情况下其他线程访问不到(使用InheritableThreadLocal可以将某个线程的ThreadLocal值在其子线程创建时传递过...

天然卷的博客 689

springboot 多线程_ThreadLocal在springboot使用中的坑

ThreadLocal 适用于变量在线程间隔离,而在方法或类间共享的场景。现在在Springboot中我做如下场景的使用:使用 Spring Boot 创建一个 Web 应用程序,使用 ThreadLocal 存放一个 Integer 的值,来暂且代表需要在线程中保存的用户信息,这个值初始是 null。在业务逻辑中,我先从 ThreadLocal 获取一次值,然后把外部传入的参数设置到 Threa...

weixin_39700220的博客 1968

ThreadLocal类解决多线程同步问题

问题引出 我们简单写一段代码,创建三个线程获取信息,代码如下 package dataStructure; public class ThreadLocalDemo { public static void main(String[] args) { new Thread(()->{Message msg = new Message() ; msg.setInfo("第一个线程"); Channel.setMessage(msg); Channel.send();} , "线程A"

sapere_aude的博客 1188

【多线程】ThreadLocal

文章目录两种典型应用场景场景1独享对象代码迭代gitThreadLocal:解决加锁性能问题什么是ConcurrentHashMap?ThreadLocalThreadLocal作用主要方法方法ThreadLocal原理及源码注意问题内存泄漏解决:内存泄漏(阿里规约,调用的最后remove())空指针异常解决: 注意强引用 弱引用 两种典型应用场景 场景1独享对象 代码迭代git 但通过加锁解决共享对象 性能问题:还存在sycnized同一时间只能处理一个的,排队问题 ThreadLocal:解决加锁

瑞新の博客:bennyrhys 3094

Java多线程与并发之ThreadLocal

1. ThreadLocal是什么?使用场景 ThreadLocal简介 ThreadLocal是线程本地变量,可以为多线程的并发问题提供一种解决方式,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 ThreadLocal使用场景 多个线程去获取一个共享变量时,要求获...

Ccww_的博客 5215

多线程中ThreadLocal详解

1. ThreadLocal是什么,是用来解决什么问题的? ThreadLocal从字面意思来理解,是一个线程本地变量,也可以叫线程本地变量存储。有时候一个对象的变量会被多个线程所访问,这个时候就会有线程安全问题,当然可以使用synchronized关键字来为该变量加锁,进行同步处理来限制只能有一个线程来使用该变量,但是这样会影响程序执行的效率,这时ThreadLocal就派上了用场; 使用T...

Helon的博客 6628

SimpleDateFormat 的多线程坑,你踩过没?

在咱们日常开发业务代码的时候,时间和日期的处理可是少不了的。说到时间处理类,估计大家对 SimpleDateFormat 都不陌生。这家伙主要用来搞定时间的格式化和解析,操作起来挺方便,速度也快得很。不过啊,SimpleDateFormat 这货有个大问题——它不是线程安全的!一旦到了多线程的场景,保不齐就得出乱子,估计有点经验的小伙伴都踩过这坑。接下来咱们就来扒一扒,为什么 SimpleDateFormat 不安全,问题咋来的,还有在多线程环境下咋整能解决。

郑龙飞 1198

多线程中ThreadLocal的使用

前言 多线程是Java的一个重要特性,多线程从某方面可以等价于多任务,当你有多个任务要处理时,多个任务一起做所消耗的时间肯定比任务串行起来做,所消耗的时间短。而对于多线程不熟悉的新手则容易踩到很多坑,最典型的则是变量问题。 概念介绍 下面先用简单粗俗的语言解释一下几个基本概念 线程安全:多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。典型的例子为StringBuffer类。 线程不安全:不提供数据

qq_41530937的博客 787
上一篇: 使用jQuery制作模态框
下一篇: 《Java网络编程》学习笔记:URL和URI(一)
FujianSun
博客等级 码龄10年 1粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值