使用 transmittable-thread-local 组件解决 ThreadLocal 父子线程数据传递问题
在某个项目中,需要使用mybatis-plus多租户功能以便数据隔离,前端将租户id传到后端,后端通过拦截器将该租户id设置到ThreadLocal以便后续使用,代码大体上如下所示:
ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();
threadLocal.set(1);
我在Controller层使用线程池取了租户id,代码大体上如下所示:
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(()->{
//获取租户id
});
这时候出问题了,出现了有时候取得到有时候取不到租户id的现象,但是经过若干次重试之后就能稳定获取到租户id;再次测试则发现如果前端传了其它的租户id,后端取得还是上一次获取到的租户id,这到底是为啥呢?
问题分析:首先,这里使用了InheritableThreadLocal为的就是实现父子线程传值,传了值也能取到,但是也不总是能取到,若干次之后就总是能取到了。看到这种现象,我们正常人的第一反应就是怀疑这里有缓存,每次使用的时候没有,使用完了就缓存起来,由于线程池在执行任务的时候并非总是使用同一条线程,当线程池中的核心线程全都缓存完了,再请求就稳定不报错了,然而有缓存的原因所以就算这时候外部请求换了一个租户id,线程池中的线程仍然使用的是老的租户id,这也是缓存最直接的体现。。。。。。这里纯属基于现象的个人猜测,并没有什么实锤,看官们谨慎驾驶,小心翻车。
那怎么解决该问题呢?
该问题产生的原因是InheritableThreadLocal的bug,至于什么bug,我也不清楚(笑),但是有解决方案,解决方案就是使用阿里的transmittable-thread-local 组件,github地址如下:https://github.com/alibaba/transmittable-thread-local 使用起来也非常简单
首先,引入maven依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.0</version>
</dependency>
1. 改变ThreadLocal的创建方式
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程中设置
context.set("value-set-in-parent");
// =====================================================
// 在子线程中可以读取,值是"value-set-in-parent"
String value = context.get();
2.改变线程池创建方式
ExecutorService executorService = ...
// 额外的处理,生成修饰了的对象executorService
executorService = TtlExecutors.getTtlExecutorService(executorService);
也就是说除了正常创建线程池之外,还要对该线程池做一个代理。
就这么简单,搞完之后父子线程传数据就一切正常了。
ps. 个人觉得这里称呼"父子线程"并不妥当,因为线程池是系统启动之后就已经创建好了的,算了,钻牛角尖太没劲了。
使用 transmittable-thread-local 组件解决 ThreadLocal 父子线程数据传递问题的更多相关文章
- 解决threadLocal父子变量传递问题
一.问题的提出 在系统开发过程中常使用ThreadLocal进行传递日志的RequestId,由此来获取整条请求链路.然而当线程中开启了其他的线程,此时ThreadLocal里面的数据将会出现无法获取 ...
- ThreadLocal父子线程之间的数据传递问题
一.问题的提出 在系统开发过程中常使用ThreadLocal进行传递日志的RequestId,由此来获取整条请求链路.然而当线程中开启了其他的线程,此时ThreadLocal里面的数据将会出现无法获取 ...
- ThreadLocal父子线程传递实现方案
介绍InheritableThreadLocal之前,假设对 ThreadLocal 已经有了一定的理解,比如基本概念,原理,如果没有,可以参考:ThreadLocal源码分析解密.在讲解之前我们先列 ...
- 使用ThreadLocal在线程内部传递数据
最近在项目中使用到了JDK提供的线程池,遇到了在多线程环境下在线程内部共享数据的问题 使用ThreadLocal 来解决线程内部共享数据的问题 定义BO package com.unicom.uclo ...
- vue2.0父子组件以及非父子组件通信
官网API: https://cn.vuejs.org/v2/guide/components.html#Prop 一.父子组件通信 1.父组件传递数据给子组件,使用props属性来实现 传递普通字符 ...
- ThreadLocal的坑--ThreadLocal跨线程传递问题
1.父子线程间的传递问题 ThreadLocal的子类InheritableThreadLocal其实已经帮我们处理好了,通过这个组件可以实现父子线程之间的数据传递,在子线程中能够父线程中的Threa ...
- InheritableThreadLocal 在线程池中进行父子线程间消息传递出现消息丢失的解析
在日常研发过程中,我们经常面临着需要在线程内,线程间进行消息传递,比如在修改一些开源组件源码的过程中,需要将外部参数透传到内部,如果进行方法参数重载,则涉及到的改动量过大,这样,我们可以依赖Threa ...
- InheritableThreadLocal类原理简介使用 父子线程传递数据详解 多线程中篇(十八)
上一篇文章中对ThreadLocal进行了详尽的介绍,另外还有一个类: InheritableThreadLocal 他是ThreadLocal的子类,那么这个类又有什么作用呢? 测试代码 p ...
- vue 2.x之组件的数据传递(一)
这是根据官方提供的脚手架vue-cli搭建,通过简单的案例来介绍vue数据的传递的方式,根据自己平时用到的,来做简单的总结: 1.父组件传递数据给子组件 父组件传递数据给子组件,需要把子组件引入,并挂 ...
随机推荐
- Java 虚拟机运行时数据区详解
本文摘自深入理解 Java 虚拟机第三版 概述 Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟 ...
- codeforces 1424J,为了过这题,我把祖传的C++都用上了!
大家好,我们选择的是Bubble Cup比赛Div2场次的J题,不用问我Bubble Cup是什么比赛,我也不清楚.总之是一场算法比赛就是了.可能是这个比赛知名度比较低吧,参与的人数也不是很多,我们选 ...
- oracle sql%notfound
SQL%NOTFOUND 是一个布尔值.与最近的sql语句(update,insert,delete,select)发生交互,当最近的一条sql语句没有涉及任何行的时候,则返回true.否则返回fal ...
- BugkuCTF-web-速度要快
打开题目显示一串文字,应该是提示. 查看源代码 OK ,now you have to post the margin what you find post提交参数margin burp发送后发现响应 ...
- JZOJ2020年8月11日提高组T2 宝石
JZOJ2020年8月11日提高组T2 宝石 题目 Description 见上帝动了恻隐之心,天后也想显示一下慈悲之怀,随即从口袋中取出一块魔术方巾,让身边的美神维纳斯拿到后堂的屏风上去试试,屏风是 ...
- (十八)面向流水线的设计:CPU的一心多用
一.单指令周期 由前可知,一条CPU指令的执行有三个步骤:指令读取.指令译码.指令执行.由于这个过程受CPU时钟的控制,如果我们将这个过程安排在一个CPU时钟周期内执行,这种设计思路就叫单 ...
- 转:【Python3网络爬虫开发实战】6.4-分析Ajax爬取今日头条街拍美图
[摘要] 本节中,我们以今日头条为例来尝试通过分析Ajax请求来抓取网页数据的方法.这次要抓取的目标是今日头条的街拍美图,抓取完成之后,将每组图片分文件夹下载到本地并保存下来. 1. 准备工作 在本节 ...
- 第2章 Python编程基础知识目录
第2.1节 简单的Python数据类型.变量赋值及输入输出 第2.2节 Python的语句 第2.3节 Python运算符大全 老猿Python,跟老猿学Python! 博客地址:https://bl ...
- PyQt(Python+Qt)学习随笔:QTableView的cornerButtonEnabled属性
老猿Python博文目录 老猿Python博客地址 cornerButtonEnabled属性用于控制是否启用左上角的按钮.如果此属性为True,则启用视图左上角的按钮,单击此按钮将选择表视图中的所有 ...
- 第15.17节 PyQt(Python+Qt)入门学习:PyQt图形界面应用程序的事件捕获方法大全及对比分析
老猿Python博文目录 老猿Python博客地址 按照老猿规划的章节安排,信号和槽之后应该介绍事件,但事件在前面的随笔<PyQt(Python+Qt)实现的GUI图形界面应用程序的事件捕获方法 ...