在某个项目中,需要使用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. 个人觉得这里称呼"父子线程"并不妥当,因为线程池是系统启动之后就已经创建好了的,算了,钻牛角尖太没劲了。

最新文章

  1. Chrome开发者工具不完全指南(五、移动篇)
  2. openstack 流量控制
  3. NHibernate使用ICriteria分页并返回数据库记录总条数
  4. 【bzoj2460】 BeiJing2011—元素
  5. Ubuntu下tftp服务搭建
  6. 1059. Prime Factors (25)
  7. Java多线程编程的常见陷阱(转)
  8. Fire Net(深搜 和一前不一样的深搜)
  9. SQL开发中容易忽视的一些小地方(五)
  10. 剑指offer_(17)
  11. [js] webgl 初探 - 绘制三角形
  12. Centos7 下安装Docke
  13. 集合(list、set和map)区别
  14. Vue 中动态添加class(使用v-bind:class)
  15. MySQL数据库的锁详解【转】
  16. 【读书笔记】iOS-OCUnit-单元测试
  17. [bug] 验证selenium的显式和隐式等待而发现的一个低级错误
  18. VMware 安装 centos,自定义分区
  19. java上传excel文件及解析
  20. Java之MD5加密

热门文章

  1. spring与分布式事务
  2. nacos单机,集群安装部署
  3. Event Loop - 事件队列
  4. ModelViewSet基础操作
  5. 第9.9节 Python文件随机读写定位操作方法seek
  6. PyQt(Python+Qt)学习随笔:Designer中QDialogButtonBox确认clicked信号是哪个按钮发送的方法
  7. sql bool盲注
  8. selenium模拟淘宝登陆,过所有验证
  9. Norns.Urd 中的一些设计
  10. C++ 有关指针作为函数参数的问题,自定义内存分配函数传递二级指针的问题