解决异步任务中访问ThreadLocal报错的方案及实现

使用Async如何传递ThreadLocal及自定义线程池 1. 当使用ThreadLocal存储数据时,程序中使用了@Async异步任务注解,后导致子任务中无法获取到ThreadLocal存储的数据2. 使用@Async注解后默认的线程池最大线程数和队列长度为 Integer.MAX_VALUE,当并发量增高后会导致系统负载飙升甚至系统宕机。 阅读详情

在这里插入图片描述

当开发软件程序时,我们通常需要异步记录操作日志和用户信息。操作日志可以用于跟踪系统的运行情况、查询问题以及审计目标的,而使用用户信息记录则可以用于个人化服务、权限管理和统计分析等等方面。然而,在某种情况下,我们可能会遇到以下问题:在异常任务中访问ThreadLocal的信息时报错。

问题现象和产生的原因

异步任务在不同的线路中执行,而ThreadLocal只在当前线路中可见。这意味着,当我们在异步任务中尝试访问之前在主线路或其它线路中设置的ThreadLocal变化量时,就会发生错误。这种错误可能会导致无法正确获取用户信息,并影响到日志记录的准确性和完整性。

解决方案一:转发用户信息(推荐)

为了解决异常步骤中无法访问ThreadLocal的问题,一种常见的解决方法是通过参数传递用户信息。具体而言,我们可以在登录验证通过滤器中,登录成功后将使用用户信息作为参数传递给异常步骤。这样,异步任务就可以直接使用传递的用户信息,而不依赖于ThreadLocal。

在现实过程中,我们需要在登录验证过滤器中获取用户信息,并将其传递给异常任务。可以通过在异常任务的结构制造数中接收用户信息参数的方式来现实。这样,在异步任务中就可以使用该用户信息,进行日志记录或其他相关操作。

解决方案二:使用InheritableThreadLocal

另一种解决方案是使用InheritableThreadLocal。InheritableThreadLocal代替ThreadLocal,它是ThreadLocal的一个子类,它可以在子线中继承父线中设置的信息。通过使用InheritableThreadLocal我们可以在主线中设置用户消息到ThreadLocal,然后在异常任务的子线程序中获得这些信息。

需要注意的是,使用InheritableThreadLocal可能会引入一些性能开发,并且需要小心处理线路之间的共享数据。在使用时,我们需要确保合适时机设置和清理中的价值,以防止内存泄漏或数据混乱InheritableThreadLocal等问题。

解决方案三:使用单线程的线程池

如果你希望登录过滤器和异步任务在同一个线程中执行,可以使用单线程的线程池来执行异步任务。这样,所有的异步任务都会在同一条线路中按顺序执行,保证登录通过滤器和异步任务的执行在同一条线路上。

在这种方案中,我们需要创建一个单线程的线程池,然后将异常步骤提交给该线程池执行。这样,所有的异常步骤事务都会在同一条线路中执行,可以确保登录过过滤器中设置的ThreadLocal中用户信息在异常操作执行期间可用。

需要注意的是,使用单线程的线程池可能会影响系统的并发性能,因为所有的异常步骤都在同一个线程中顺序执行。因此,该方案适合用于对并发性能要求不高的场景。

方案一详细实现步骤

这里用一个简单的demo项目演示方案一的详细解决步骤

模拟记录操作日志,在查询方法加上Log自定义注解,前端发起请求执行该方法就会执行记录操作日志。

在这里插入图片描述

1、过滤器对请求进行过滤和放行,判断session中是否有用户信息。

在这里插入图片描述
2、如果session中有用户信息则查询数据库校验用户信息,校验通过后返回用户信息。

在这里插入图片描述
3、将用户信息存入session中,下一次请求就会携带用户信息。

在这里插入图片描述
4、将用户信息存入ThreadLocal中并放行。

在这里插入图片描述
5、进入AOP方法增强代码,处理日志信息,这里可以获取到ThreadLocal信息。

在这里插入图片描述
6、处理日志信息方法也可以获取ThreadLocal信息,通过参数传递的方式将用户信息传递给异步任务方法。

在这里插入图片描述
7、进入异步任务方法,这里可以看到通过方法传参可以获取到用户信息,而使用ThreadLocal则获取不到用户信息。

在这里插入图片描述
8、执行SQL将操作日志信息写入到数据库中。

在这里插入图片描述

以上是针对该问题的几种解决方案。具体选择哪种解决方案需要根据具体的业务和需求进行相应的调整。
在这里插入图片描述

SaToken 1.37 异步线程上下文丢失:3种场景分析与2种解决方案实测 本文深入分析了SaToken 1.37在异步线程中Web上下文丢失的问题,提供了3种常见场景的详细解析和2种实测有效的解决方案。针对`@Async`异步调用、手动创建子线程和RPC调用等场景,推荐参数透传和上下文重置方案,帮助开发者有效解决`SaTokenException: 非Web上下文无法获取Request`异常。 阅读详情

相关推荐

不当使用ThreadLocal导致的错误 - 前端

为了避免可能的错误,我们应该注意在使用完ThreadLocal后进行清理操作,并在使用线程池时显式地清除ThreadLocal中的数据。例如,在Web应用程序中,当一个请求处理完毕后,对应的线程也应该结束,但线程本身可能会被线程池缓存以备重用,这时ThreadLocal中的数据就会残留下来。为了确保在多线程环境下的数据安全性,Java中的ThreadLocal类常被使用。在上面的修改后的代码中,我们添加了一个clearContext方法,该方法在使用完ThreadLocal后调用,以清除当前线程中的变量。

AvskBug的博客 254

【JUC并发编程】14 TransmittableThreadLocal解决线程池中ThreadLocal无法在父子线程之间传递的问题

TransmittableThreadLocal如何使用? 如何解决线程池中ThreadLocal无法在父子线程之间传递的问题?

健身变秃,coding变强 2597

Spring定时任务中使用ThreadLocal的坑

NULL 博文链接:https://bijian1013.iteye.com/blog/2380233

Java多线程10:ThreadLocal的作用及使用

ThreadLocal的作用 从上一篇对于ThreadLocal的分析来看,可以得出结论:ThreadLocal不是用来解决共享对象的多线程访问问题的,通过ThreadLocal的set()方法设置到线程的ThreadLocal.ThreadLocalMap里的是是线程自己要存储的对象,其他线程不需要去访问,也是访问不到的。各个线程中的ThreadLocal.ThreadLocalMap以及Th...

weixin_33836874的博客 276

LabVIew串口收发的一些问题

LabView串口收发实验总结

weixin_45508826的博客 2065

Win11系统下Abaqus2022与VS2022+oneAPI2023环境配置全攻略(附VUMAT子程序避坑指南)

本文详细指导在Windows 11系统下,为Abaqus 2022配置Visual Studio 2022与Intel oneAPI 2023的Fortran编译环境,以支持VUMAT等用户子程序开发。内容涵盖软件安装顺序、环境变量关联、快捷方式修改及关键验证步骤,并提供了首个VUMAT子程序的实战编写与模型验证方法,帮助用户高效搭建稳定可靠的仿真开发平台。

pytorch8learner的博客 316

@Async 异步任务的五个坑

本文深入剖析了Spring中@Async异步任务注解的五个常见陷阱,通过可运行的demo和真实日志展示了问题现象与解决方案。

Leighteen 246

Nengo神经工程框架:脉冲神经网络的实时编译与硬件部署

脉冲神经网络(SNN)作为类脑计算的核心范式,正从生物模拟走向工程落地。其本质是用离散脉冲建模神经动力学,关键在于实现可预测、可复现的神经行为而非单纯拟合函数。Nengo基于神经工程学框架(NEF),将动态系统理论与硬件约束深度融合,通过解析式权重计算、确定性时间步长(dt)和多后端编译能力,支撑从CPU仿真到Loihi/FPGA的端到端部署。它不替代深度学习框架,而是提供面向神经形态芯片的‘神经编译器’能力,使LIF神经元参数、突触动力学与硬件时序严格对齐,显著提升实时性、能效比与物理可解释性。

weixin_32533659的博客 636

《Spring 中上下文传递的那些事儿》Part 7:异步任务上下文丢失问题详解

在现代 Java 应用中,异步编程已经成为提升性能、解耦业务逻辑的重要手段。无论是使用 CompletableFuture、线程池(ExecutorService)、定时任务(ScheduledExecutorService),还是 Spring 的 @Async 注解,我们都可能遇到一个共同的问题:上下文信息丢失。 本文将带你深入理解为什么异步任务中会出现上下文丢失,并提供多种解决方案,包括手动拷贝、TTL 封装、AOP 自动注入等,帮助你在各种场景下都能正确地传递上下文。

Good good study,day day up 1568

【AI大模型应用开发】教你用AI轻松将你的知识库变为知识图谱(附完整代码,直接运行)

本文我们来介绍如何使用AI,将自己的知识库自动转换为知识图谱,并进行可视化展示。

同学小张的博客 3927

18、基于FSDD数据集的深度学习案例分析

本文基于FSDD(Free Spoken Digit Dataset)数据集,系统介绍了深度学习在语音数字识别中的应用。内容涵盖动态与静态计算图的对比、数据预处理流程(包括数据增强、固定长度处理和归一化)、监督学习与无监督学习的模型构建与训练过程,并通过实验对比了不同网络架构的性能。文中使用PyTorch实现2层全连接网络和自编码器模型,展示了正则化技术对提升模型准确率的关键作用。最后总结了关键技术并提出了实际应用建议,展望了未来在复杂模型、多模态融合和实时应用方向的发展潜力。

vscode6remote的博客 259

Spring 异步线程中传递ThreadLocal

ThreadLocal 的传递

keep_learn的专栏 1759

基于YOLOv8的MVTec AD缺陷检测系统设计与实现

速度快,精度高;支持 anchor-free 架构;支持实例分割和图像分类;模块化代码,易于部署与改进;完美兼容 ONNX、TensorRT 等推理框架;官方支持多平台训练和推理(CPU/GPU)。YOLOv8 是工业视觉检测落地非常理想的选择。MVTec AD(Anomaly Detection)数据集包括15类工业对象,每个对象包括多个子类缺陷(例如 “scratch”, “crack”, “hole”)及正常图像。类别缺陷子类bottlecablecapsule。

YOLO 931

线程切换,线程异步,异步线程, 上下文 传递, threadLocal的处理

当代码中, 录制回放单测拦截中使用了threadLocal上下文时. 异步时就需要上下文切换. 如果做的不好,就会导致上下文未清除.上下文就乱了. 第一次是空,后面再使用到该线程时就不为空,就一直是第一次的上下文了. 除非你在finnally里清空掉.TestContext: 单测中使用的上下文 TestContext.getInstance();但是你不知道你当前的接口的后面是不是还要用TestContext.getInstance()// 执行业务逻辑.在异步线程后,肯定是会报错的.

fei33423的专栏 680

整车电检工艺流程

本文是笔者在从事汽车行业智能制造领域过程,对于整车电检工艺流程的理解与总结。

qq_40664711的博客 1万+

YOLOv11改进策略【卷积层】| 引入注意力卷积模块RFAConv,关注感受野空间特征 助力yolov11精度提升

RFAConv:创新空间注意力和标准卷积运算感受野空间特征是针对卷积核设计的,根据卷积核大小动态生成。以3×3卷积核为例,它由非重叠滑动窗口组成,每个窗口代表一个感受野滑块。

Limiiiing的博客 1823

Spring Boot异步任务里RequestContextHolder为啥拿不到request?一个参数就搞定

本文深入解析了Spring Boot异步任务中RequestContextHolder无法获取request对象的原因,并提供了通过设置`setRequestAttributes`的第二个参数`true`来启用InheritableThreadLocal的解决方案。文章详细探讨了ThreadLocal的线程隔离特性、解决方案的适用场景与限制,以及与其他异步组件的整合方法,帮助开发者高效处理异步任务中的request对象访问问题。

weixin_30906185的博客 337

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Feign异步远程调用丢失请求头的两种解决方法

4、由代码可知,请求信息是从requestAttributesHolder 中获取的,而 requestAttributesHolder 类型为 ThreadLocal,即本地线程。异步任务直接使用线程池里的线程去执行方法,而不是继续使用原有线程,导致无法继续使用原线程中的数据。5-2-1、ThreadLocal 的子类 InheritableThreadLocal 可以使让子线程继承父线程的信息。5-2-2、因此,可以通过语句,在异步调用前将父线程中的请求信息绑定给子线程。

m0_51614605的博客 1337

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

AsnycLocal与ThreadLocal

【代码】AsnycLocal与ThreadLocal。

极客神殿 853

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Spring Boot 异步线程间数据传递的优雅实现

日常开发都使用ThreadLocal来存取用户信息等全局遍历,但是当遇到了多线程,ThreadLocal就失效了,以下提供2种方法帮助我们优雅实现线程间的数据传递。

qq_22918201的博客 551

慎用 @Async:从 ThreadLocal 失效到 Cookie 丢失的连环坑

摘要: 线上导出接口因@Async异步调用导致Cookie丢失,触发文件中心鉴权失败。问题根源在于异步线程无法继承主线程的HttpServletRequest上下文,且请求对象在主线程结束后失效。解决方案包括:提取必要参数(如Cookie)而非传递Request、使用InheritableThreadLocal传递上下文,或重构逻辑避免跨服务异步调用。此外,@Async还存在异常处理黑洞(需实现AsyncUncaughtExceptionHandler)、事务失效(需分离异步与事务方法)及线程池耗尽(需自定

dom_jun的博客 905

Spring Security异步无法获取用户认证信息

InheritableThreadLocal可以获取到子线程信息‌,主要是因为它是ThreadLocal的一个子类,设计用来在父子线程间传递数据。具体来说,当父线程创建一个子线程时,这通常涉及到在子线程的Thread对象中复制父线程的ThreadLocalMap,从而使子线程能够访问到父线程中设置的变量。需要注意的是,虽然InheritableThreadLocal提供了在子线程中访问父线程数据的能力,但它并不适用于所有情况,然而,在某些情况下,我们需要父线程中的数据能够在由父线程创建的子线程中被访问,

rt5476238的博客 1470

包装CompletableFuture的异步任务让其开启事务(加入主线程事务不可取)

核心问题:事务的ACID特性与多线程资源共享存在本质冲突Session/Connection非线程安全数据库连接和JPA Session设计为单线程使用多线程同时操作同一连接会导致SQL执行顺序混乱、状态覆盖操作原子性无法保证看似"都完成"实际是假象,存在数据竞争风险一个线程的操作可能被另一个线程覆盖,且不会抛出异常违反事务"要么全完成,要么全不完成"的基本原则隔离级别失效多线程并发修改使数据库隔离机制形同虚设脏读、不可重复读、幻读问题无法避免。

qq_64000191的博客 746

Java日志追踪实战:MDC原理、配置与异步场景解决方案

在分布式系统和微服务架构中,日志追踪是提升系统可观测性的关键技术。其核心原理是通过线程绑定的上下文容器,为每个请求关联唯一标识,实现日志的串联与聚合。这项技术的核心价值在于能够显著提升问题排查效率,支持链路追踪和日志分析。在实际应用场景中,它广泛用于Web请求处理、异步任务执行和微服务间调用。本文聚焦于SLF4J MDC(映射诊断上下文)的实现,详细解析其基于ThreadLocal的设计,并通过日志框架集成、Spring Boot实战配置,特别是针对异步场景下MDC传递的解决方案,如使用TaskDecora

weixin_34224941的博客 405

使用 transmittable-thread-local 组件解决 ThreadLocal 父子线程数据传递问题

在某个项目中,需要使用mybatis-plus多租户功能以便数据隔离,前端将租户id传到后端,后端通过拦截器将该租户id设置到ThreadLocal以便后续使用,代码大体上如下所示: ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>(); threadLocal.set(1); 我在Controller层使用线程池取了租户id,代码大体上如下所示: ExecutorService executorServ

狂盗一枝梅的专栏 2229

Feign配置RequestContextHolder.getRequestAttributes()为null的解决方案

Feign配置RequestContextHolder.getRequestAttributes报NullPointException问题出现场景分析原因关于RequestContextHolder原因解决方案 问题出现场景 feign配置如下 异步代码中调用feign 当用在异步代码中用feign调用微服务时,后台日志中出现报错信息NullPoinntException 分析原因 关于RequestContextHolder 实现原理 ThreadLocal ThreadLocal是一个本地线程副本变

07feng的博客 8056
上一篇: SpringBoot整合RabbitMQ实现RPC远程调用功能
下一篇: Python基础学习笔记
霁晨晨晨
博客等级 码龄4年 359粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霁晨晨晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值