首页 > 其他分享 >关于ThreadLocal 保存信息用于存储通用信息

关于ThreadLocal 保存信息用于存储通用信息

时间:2025-01-15 14:55:34浏览次数:1  
标签:存储 vendorInfo 保存信息 VendorInfo ThreadLocal 线程 VendorContext public

     近期项目中由于使用ThreadLocal 造成一次生产事故,所以对ThreadLocal进行整理说明,来对ThreadLocal进行总结以备后续更好的使用。

  一、 ThreadLoca 事故说明

   事故说明 首先在程序中定义了静态商家List对象 List<VenderInfo> listVender ,并对期进行了数据初始化,然后第一个线程从listVender 取出一个对象放入 ThreadLocal, 当第二个线程请求进来再从listVender取出一个对象与第一个线程取出的对象相同 并对该对象进行修改,此时第一个线程中ThreadLocal存储的对象属性值已经被修改,因为修改了同一个引用类型的对象,并不是ThreadLocal 的信息被混用了。由于以上描述情况导致 第一个线程ThreadLocal存储对象的属性值被修改,再使用时出现错乱使业务数据存储StoreId信息不正确,影响业务数据。所以如果在ThreadLocal中放对象时1、放入后不要修改  2、在放入时 copy一个新对象。

//根据商家Id,获取商家信息
        VendorInfo vendorInfo = VendorContext.getVendorInfoByAreaId(areaId);
        vendorInfo.setRequestStoreId(storeId);
        vendorInfo.setRequestAreaId(areaId);

//把商家信息放入当前线程中VendorContext ThreadLocal 封装对象
VendorContext.setVendorInfo(vendorInfo);

  

二、ThreadLocal 使用实例

      概述:ThreadLocal 用于存储好多位置都使用的通用信息 一次取出后多次使用,类似于Session的使用。

    1、创建ThreadLocal 存储类用于更新存储请求通用信息 其实可以说是Session

       

public class VendorContext {

    private static final   ThreadLocal<VendorInfo> threadLocalInfo= new ThreadLocal<VendorInfo>();
    static List<VendorInfo> listV=new ArrayList<>();

     public static void beforeSetData() throws Exception {
        VendorInfo vendorInfo = new VendorInfo();
        vendorInfo.setVendorId("123");
        listV.add(vendorInfo);
        // 再加一个vendorInfo
        VendorInfo vendorInfo2 = new VendorInfo();
        vendorInfo2.setVendorId("456");
        listV.add(vendorInfo2);
    }


    /**
     * 设置threadLocal
     * @param areaId
     */
    public static void setVendorInfo(String areaId){
        VendorInfo vendorInfo= listV.get(0);
        vendorInfo.setRequestStoreId("66"+areaId);
        VendorInfo vendorInfo1 = new VendorInfo();
        // 注意该部分一定要copy一下,用新对象,否则会出现线程安全问题,线程2修改对象vendorInfo 会影响线程1的数据
        BeanUtil.copyProperties(vendorInfo, vendorInfo1);
        threadLocalInfo.set(vendorInfo1);
    }

    public static VendorInfo getVendorInfo(){
        return threadLocalInfo.get();
    }

    /**
     * 清除threadLocal
     */
    public static  void clearVendorInfo(){
        threadLocalInfo.remove();
    }

}

2、新加拦截器 为VendorContext 中ThreadLocal对象赋值

/**
 * 拦截器设置 threadLocal 线程变量,用于本次会话的数据传递
 *
 * ps:特别注意,
1 、每个线程数据被感染,如存放一个引用类型的数据, * 线程变量的清除,一定要在finally中清除,否则会导致线程变量污染
2、每次使用完以后都需要清理 VendorContext.clearVendorInfo(); 因为线程有重复使用的时候,不能感染后续线程使用。 * * */ @Component @Slf4j public class RequestInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String areaId= request.getHeader("areaId"); VendorContext.setVendorInfo(areaId); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { VendorContext.clearVendorInfo(); } }

 

3、 将拦截器加入springboot  MVC 请求配置中

  

@Configuration
public class MvcConfig  implements WebMvcConfigurer {

    @Resource
    RequestInterceptor requestInterceptor;


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(requestInterceptor).addPathPatterns("/**");
    }
}

 

3、在业务模块中使用ThreadLocal 封装类VendorContext

 public  VendorInfo vendorInfo2;
    @RequestMapping("/getViewInfo")
    public UserInfo getView() {
        UserInfo userInfo= new UserInfo();
        userInfo.setUserName("123");
        // 获取threadLocal 数据
        VendorInfo vendorInfo= VendorContext.getVendorInfo();
        if(vendorInfo2==null){
            vendorInfo2=vendorInfo;
        }
        if(vendorInfo==vendorInfo2){
            System.out.println(" = ====" );
        }

        // 多线中使用threadLocal,要再次为 VendorContext.setVendorInfo赋值,用完以后要清除
         new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    VendorContext.setVendorInfo(vendorInfo.getRequestAreaId());
                    VendorInfo vendorInfo= VendorContext.getVendorInfo();
                    System.out.println("vendorInfo.getRequestStoreId() = " + vendorInfo.getRequestStoreId());
                } catch (Exception ex){
                    ex.printStackTrace();
                }
                finally {
                    VendorContext.clearVendorInfo();
                }
            }}).start();
        return userInfo;
    }

 

 

  

 

  

 

 

      

标签:存储,vendorInfo,保存信息,VendorInfo,ThreadLocal,线程,VendorContext,public
From: https://www.cnblogs.com/liyanbofly/p/18672904

相关文章

  • doris:远程存储
    概述​远程存储支持将冷数据放到外部存储(例如对象存储,HDFS)上。注意远程存储的数据只有一个副本,数据可靠性依赖远程存储的数据可靠性,您需要保证远程存储有ec(擦除码)或者多副本技术确保数据可靠性。使用方法​冷数据保存到S3兼容存储​第一步: 创建S3Resource。CREATE......
  • MySQL(高级特性篇) 07 章——InnoDB数据存储结构
    一、数据库的存储结构:页索引结构给我们提供了高效的索引方式,不过索引信息以及数据记录都是保存在文件上的,确切地说是存储在页结构中。另一方面,索引是在存储引擎中实现的,MySQL服务器上的存储引擎负责对表中数据的读取和写入工作。不同存储引擎中存放的格式一般是不同的,甚至有的......
  • 跟我一起学 Python 数据处理(三十八):数据案例实战与存储要点解析
    跟我一起学Python数据处理(三十八):数据案例实战与存储要点解析在数据处理的学习之旅中,我们致力于与各位共同成长,探索数据的奥秘。上两篇博客分别介绍了多种数据来源和获取方法,今天我们将通过实际案例进一步深化理解,并着重探讨数据存储方面的关键知识。一、案例深度剖析(一......
  • k8s OpenLocal存储
    参考项目https://github.com/alibaba/open-localv0.7.1NodeLocalStorage定义NodeLocalStoragecr表示每个k8s节点本地存储资源信息。controller创建后由节点上agent更新status,从而维护存储信息。apiVersion:csi.aliyun.com/v1alpha1kind:NodeLocalStoragespec:nodeName......
  • C:\Users\Administrator\Local Settings\temp 是 Windows 操作系统中的一个临时文
    C:\Users\Administrator\LocalSettings\temp是Windows操作系统中的一个临时文件夹,通常用于存储操作系统和应用程序在运行时生成的临时数据。具体来说,temp文件夹用于存放临时文件,例如:安装文件:一些程序在安装过程中会将临时文件放在这里。缓存文件:一些程序可能会将数据缓存......
  • 仅需一个插件让关系型数据库实现图数据存储与检索
    简介ApacheAGE是一个PostgreSQL数据库的扩展插件,使得在关系型数据库中也可以使用openCypher查询语言进行图查询。有了该插件,可以在PostgreSQL数据库中同时实现关键字检索、向量检索、图检索,仅需一个数据库即可实现复杂RAG的各种存储和检索需求。安装Docker安装获取镜像doc......
  • 【C语言】浮点型数据的存储详细讲解
    ​在引入知识之前,先来看一个案例,就知道了解浮点型数据存储的重要性与必要性。举个例子:#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h> intmain(){ intnum=9; float*pnum=(float*)&num;//强制转换类型 printf("n的值为:%d\n",n); printf("*pFloat......
  • 存储引擎-2
    存储引擎的查看查看MySQL默认存储引擎select@@default_storage_engine;查看表存储引擎selecttable_schema,table_name,enginefrominformation_schema.tableswheretable_schemanotin('sys','mysql','information_schema','performance_schema'......
  • 定时抓取数据:Python爬虫与定时任务实现每日数据采集与存储
    引言在现代数据驱动的世界中,实时获取和存储数据是许多应用的核心需求。无论是金融行业的实时汇率监控,还是电商行业的价格变化追踪,定时抓取数据都是一种高效的数据采集方式。本文将详细介绍如何使用Python结合爬虫技术和定时任务,实现每天定时抓取数据并将其存入数据库。一......
  • 数据在内存的存储
    数据类型介绍前面我们已经学习了基本的内置类型:(后边跟的是字节)char    //字符数据类型  1字节 打印%c      short   //短整型    2字节  打印%hdint    //整形    4字节  打印%dlong ......