JUC(三)ThreadLocal

简介: JUC(三)ThreadLocal

@[toc]

前言

前段时间我不是做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();

这些解释是我在关注的两位博主文章中看到的,沉默王二三太子敖丙,希望有一天也可以成为像他们一样的大佬

相关文章
|
存储 芯片 内存技术
DRAM集中刷新,分散刷新,异步刷新的区别
DRAM集中刷新,分散刷新,异步刷新的区别
1650 0
|
9月前
|
人工智能 自然语言处理 JavaScript
Aider:27.6K Star!这个终端AI编程神器能用语音改代码,自动生成Git记录并提交,接入DeepSeek斩获编程基准最高分
Aider 是一款基于命令行的开源 AI 编程助手,支持多种编程语言和主流 LLM,可自动完成代码修改、Git 提交及语音交互。
1349 1
|
10月前
|
SQL 关系型数据库 MySQL
docker-compose部署mysql8
使用docker-compose容器化部署mysql8
767 7
|
SQL 人工智能 自然语言处理
如何诱导AI犯罪-提示词注入
我们用到的大模型基本把政治类信息、犯罪相关信息都已屏蔽。但是,黑客依旧可以使用提示词诱导和提示词注入的方式对大模型进行攻击。
如何诱导AI犯罪-提示词注入
|
SQL 关系型数据库 MySQL
基于proxysql实现MySQL读写分离
基于proxysql实现MySQL读写分离
490 0
|
算法 Linux 计算机视觉
OPEN CV 环境配置 VS 2022(超详细+图解)
OPEN CV 环境配置 VS 2022(超详细+图解)
949 0
|
分布式计算 Hadoop Java
centos 部署Hadoop-3.0-高性能集群(一)安装
centos 部署Hadoop-3.0-高性能集群(一)安装
476 0
|
Python
PyEMD包安装导入踩坑
PyEMD包安装需要注意的地方
1366 1
|
关系型数据库 MySQL 开发工具
Mysql 忘记密码怎么重置密码(详细步骤)
Mysql 忘记密码怎么重置密码(详细步骤)
1463 0
|
芯片
STM32——IIC基础知识及例程使用(后续拓展)
STM32——IIC基础知识及例程使用(后续拓展)
760 1
STM32——IIC基础知识及例程使用(后续拓展)