当前位置:网站首页>JUC(三)ThreadLocal
JUC(三)ThreadLocal
2022-04-22 15:57:00 【fate急速出击】
文章目录
前言
前段时间我不是做MP的动态表名嘛,详见Mybatis-Plus 动态表名,然后我去MP的动态表名的demo中看到了动态表名的传值方式,没错就是ThreadLocal。
- 这个是他的传递辅助类
public class RequestDataHelper {
/** * 请求参数存取 */
private static final ThreadLocal<Map<String, Object>> REQUEST_DATA = new ThreadLocal<>();
/** * 设置请求参数 * * @param requestData 请求参数 MAP 对象 */
public static void setRequestData(Map<String, Object> requestData) {
REQUEST_DATA.set(requestData);
}
/** * 获取请求参数 * * @param param 请求参数 * @return 请求参数 MAP 对象 */
public static <T> T getRequestData(String param) {
Map<String, Object> dataMap = getRequestData();
if (CollectionUtils.isNotEmpty(dataMap)) {
return (T) dataMap.get(param);
}
return null;
}
}
- 附 我的替换表名的拦截器代码
@Configuration
@MapperScan("com.cars.ysdd.clts.domain.clts.dao")
public class MybatisPlusConfig {
static List<String> tableList(){
List<String> tables = new ArrayList<>();
tables.add("user");
return tables;
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
// 获取参数方法
String newTable = null;
for (String table : tableList()) {
newTable = RequestDataHelper.getRequestData(table);
if (table.equals(tableName) && newTable!=null){
tableName = newTable;
break;
}
}
return tableName;
});
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
return interceptor;
}
}
然后代码中是这么使用的。
RequestDataHelper.setRequestData(new HashMap<String, Object>() {
{
put("user", "user_2018");
}});
那会儿就纳闷如果有并发的话,肯定会出问题啊,然后我就想试试,于是我新开了个线程进行赋值。
RequestDataHelper.setRequestData(new HashMap<String, Object>() {
{
put("user", "user_2019");
}});
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
RequestDataHelper.setRequestData(new HashMap<String, Object>() {
{
put("user", "user_2018");
}});
});
completableFuture.get();
User user = userMapper.selectById(1);
//sql-> select * from user_2019 where id = 1
最后发现执行的sql表名居然还是user_2019,可明明user_2018是最后赋值的呀,带着疑惑我去研究了。
ThreadLocal
后来一想,ThreadLocal这个类名可以顾名思义的进行理解,表示线程的“本地变量”,即每个线程都拥有该变量副
本,达到人手一份的效果,各用各的这样就可以避免共享资源的竞争。
ThreadLocal的作用主要是做数据隔离,填充的数据只属于当前线程,变量的数据对别的线程而言是相对隔离的,
在多线程环境下,如何防止自己的变量被其它线程篡改。
有什么问题?
ThreadLocal在保存的时候会把自己当做Key存在ThreadLocalMap中,正常情况应该是key和value都应该被外界强引用才对,但是现在key被设计成WeakReference弱引用了。
只具有弱引用的对象拥有更短暂的生命周期,在垃圾回收器线程扫描它所管辖的内存区域的过程中,
一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
这就导致了一个问题,ThreadLocal在没有外部强引用时,发生GC时会被回收,如果创建ThreadLocal的线程一直持续运行,那么这个Entry对象中的value就有可能一直得不到回收,发生内存泄露。
就比如线程池里面的线程,线程都是复用的,那么之前的线程实例处理完之后,出于复用的目的线程依然存活,所以,ThreadLocal设定的value值被持有,导致内存泄露。
解决办法
最后给他清空就行了
REQUEST_DATA .remove();
版权声明
本文为[fate急速出击]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_43627706/article/details/124337892
边栏推荐
猜你喜欢

343-Leetcode 反转字符串中的元音字母

使用js完成文字根据输入框内数字在屏幕上移动

报名开启|QKE 容器引擎托管版暨容器生态发布会!

建筑业未来的发展方向:数字化工厂管理系统

NFT 平台安全指南

SQL statement - multi table joint query

Sign up to open QKE container engine hosting version and container ecological Conference!

哈希表篇(二)

SAP UI5 应用开发教程之七十一 - SAP UI5 页面的嵌套路由试读版

How can AI intelligent video technology be applied to the scene of daily maintenance and supervision of cultural relics and historic buildings?
随机推荐
类人猿手游内存技术教程
单选按钮选中
All the goods in the files backed up by Taobao assistant were put on the shelves again
直播app源码,随着页面上下滚动自动吸顶
设置json编码
Crystal Chem 大豆 ELISA 试剂盒 II说明书
【基于合泰HT32F52352+oled温湿度显示】
[binary number] same tree
Altium designer 生成PCB制作文件及打样流程(以嘉立创商城为例)
LeetCode每日一题——824. 山羊拉丁文
Sending non-protected broadcast
jsp回显
【acwing】1135. 新年好***(dijkstra+堆优化)
Greenplum【环境搭建 05】GP最新版本v6.20.3配置安装验证(内核参数+初始化参数说明)
342-Leetcode 字符串中的第一个唯一字符
Build your own web site (8)
SQL statement - Multi - table Associated Query
Small pit on the definition of two-dimensional or multi-dimensional array / slice in go language
4.21 summary
远程桌面失败解决办法