解决ThreadLocal在项目中的线程数据共享问题

目录

ThreadLocal 简介

问题描述

为什么会有这个问题

解决方案

1. 使用请求作用域存储

2. 使用 HTTP Session 存储

3. 使用 Spring Security

4. 确保 ThreadLocal 的正确使用

5.通常解决方法

结论


在多线程环境中,ThreadLocal 是一种非常有用的工具,它允许我们为每个线程创建一个变量副本。然而,在 Web 应用或服务中,ThreadLocal 有时会导致数据共享问题,特别是在不同线程尝试访问相同请求数据的场景中。本文将探讨 ThreadLocal 的工作原理,并提供一些解决方案来确保在项目的不同线程中能够正确获取数据。

ThreadLocal 简介

ThreadLocal 是 Java 提供的一个用于创建线程局部变量的类。通过 ThreadLocal,每个线程可以拥有自己的变量副本,这意味着在多线程环境中,每个线程可以独立地改变自己的副本,而不会影响其他线程中的副本。

问题描述

在 Web 应用中,我们经常需要在不同的请求处理线程之间共享数据。然而,由于 ThreadLocal 的线程局部性,不同线程之间默认是不能共享 ThreadLocal 数据的。这会导致在某些线程中通过 ThreadLocal.get() 获取到 null 的问题。

为什么会有这个问题

  1. 线程隔离:ThreadLocal的值是线程隔离的,每个线程都有自己的副本
  2. Tomcat线程池:Tomcat使用线程池处理请求,不同的请求可能由不同的线程处理
  3. 生命周期:ThreadLocal的值仅在当前线程的生命周期内有效

解决方案

1. 使用请求作用域存储

在 Spring 框架中,我们可以使用请求作用域(Request 作用域)来存储数据,而不是依赖 ThreadLocal。这样可以确保在同一个请求中可以访问到之前存储的数据。

java

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;// 存储数据
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
attributes.getRequest().setAttribute("user", user);// 获取数据
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Users user = (Users) attributes.getRequest().getAttribute("user");

2. 使用 HTTP Session 存储

如果您需要在多个请求之间保持用户状态,可以考虑使用 HTTP Session 来存储用户信息。

java

// 存储数据到 Session
HttpSession session = request.getSession();
session.setAttribute("user", user);// 从 Session 获取数据
Users user = (Users) session.getAttribute("user");

3. 使用 Spring Security

如果您的应用使用了 Spring Security,那么可以通过 SecurityContextHolder 来获取认证信息,而不需要手动管理 ThreadLocal

java

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {Users user = (Users) authentication.getPrincipal();
}

4. 确保 ThreadLocal 的正确使用

如果您仍然需要使用 ThreadLocal,确保在请求结束时清除 ThreadLocal 中的数据,以避免内存泄漏,并确保在请求开始时设置数据。

java

// 在请求开始时设置
ThreadLocalUtil.set(user);// 在请求结束时清除
ThreadLocalUtil.remove();

5.通常解决方法

在拦截器中拦截到session的值,再将session值获取到,设置到ThreadLocal,对于每个http请求,都意味着不同的ThreadLocal,都拦截下来,重新给ThreadLocal赋值

 @Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 1. 从session获取用户信息HttpSession session = request.getSession();Users user = (Users) session.getAttribute("user");// 登录 URLString loginUrl = request.getContextPath() + "/user/login";// 如果是登录请求,直接放行if (request.getRequestURI().equals(loginUrl)) {return true;}if (user == null) {throw new LoginException("请登录!");}// 2. 设置到ThreadLocalThreadLocalUtil.set(user);return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {// 3. 请求结束后清理ThreadLocalUtil.remove();}

拦截器记得在mvc中注册

结论

ThreadLocal 是一个强大的工具,但在 Web 应用中可能会导致数据共享问题。通过使用请求作用域存储、HTTP Session 或 Spring Security,我们可以确保在项目的不同线程中能够正确获取数据。同时,正确管理 ThreadLocal 的生命周期也是非常重要的,以避免内存泄漏和其他潜在问题。通过这些方法,我们可以充分利用 ThreadLocal 的优势,同时避免其潜在的陷阱。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/62296.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

瑞芯微开发板 烧写固件问题

自用rk3568-firefly-itx-3568q核心板fpga自研底板,因底板所需外设、功能与原厂有较大差异,故裁剪相应sdk,编译新的内核进行烧写。然而在更改设备树过程中kernel/drivers/media/i2c/fpga.c中的像素格式MEDIA_BUS_FMT_YUYV8_2X8误改成MEDIA_BUS…

photoblog解题过程

本题要求:通过sql注入,找到数据库中的账号密码,并成功登录。登录后利用文件上传,将一句话木马上传到数据库中,然后并对网站进行控制。 解题过程 1、通过在靶机中输入ifconfig,查到ip为192.168.80.153&…

QT获取tableview选中的行和列的值

查询数据库数据放入tableview(tableView_database)后 QSqlQueryModel* sql_model new QSqlQueryModel(this);sql_model->setQuery("select * from dxxxb_move_lot_tab");sql_model->setHeaderData(0, Qt::Horizontal, tr("id&quo…

「Mac玩转仓颉内测版46」小学奥数篇9 - 基础概率计算

本篇将通过 Python 和 Cangjie 双语实现基础概率的计算,帮助学生学习如何解决简单的概率问题,并培养逻辑推理和编程思维。 关键词 小学奥数Python Cangjie概率计算 一、题目描述 假设有一个袋子中有 5 个红球和 3 个蓝球,每次从袋子中随机…

Face2QR:可根据人脸图像生成二维码,还可以扫描,以后个人名片就这样用了!

今天给大家介绍的是一种专为生成个性化二维码而设计的新方法Face2QR,可以将美观、人脸识别和可扫描性完美地融合在一起。 下图展示为Face2QR 生成的面部图像(第一行)和二维码图像(第二行)。生成的二维码不仅忠实地保留…

电子商务人工智能指南 1/6 - 搜索、广告和发现

介绍 81% 的零售业高管表示, AI 至少在其组织中发挥了中等至完全的作用。然而,78% 的受访零售业高管表示,很难跟上不断发展的 AI 格局。 近年来,电子商务团队加快了适应新客户偏好和创造卓越数字购物体验的需求。采用 AI 不再是一…

Python快速入门二:Python3 基础语法

一、编码 默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串。 当然你也可以为源码文件指定不同的编码: # -*- coding: cp-1252 -*-上述定义允许在源文件中使用 Windows-1252 字符集中的字符编码,对应适…

nextcloud云盘的部署

借鉴链接:https://blog.csdn.net/guigenyi/article/details/126692747 创建自定义 Docker 网络 docker network create nextcloud-network 创建mysql的账号密码都是root 并将其连接到自定义网络 docker run --name mysql-container --network nextcloud-network -e…

图(dfs与bfs)算法1

开辟新专题!不擅长的图它来了来了!(莫名激动 进度:10/100 另:没想到给自己挖了个坑,可以用dfs的基本上也可以用bfs,看来要双线并行了。 补:图算法是我近期得有30%的焦虑来源了&am…

Ruby On Rails 笔记3——表的增删改查

1.Migration Migrations是一种便利的方法,能以重现的方式随时间推移改变数据库schema. 使用Ruby Domain Specific Language (DSL),因此你不用手写SQL,进而使你的schema和changes与数据库独立。 可以把每次migration看作是数据库的一个新“版本”。A schema开始时什么都没有…

一、测试工具LoadRunner Professional脚本编写-录制前设置

设置基于URL的脚本 原因:基于HTML的脚本会导致login接口不能正确录制 设置UTF-8 原因:不勾选此项会导致脚本中文变为乱码

14、鸿蒙学习——管理通知角标

针对未读的通知,系统提供了角标设置接口,将未读通知个数显示在桌面图标的右上角角标上。 通知增加时,角标上显示的未读通知个数需要增加。 通知被查看后,角标上显示的未读通知个数需要减少,没有未读通知时&#xff0…

Thonny IDE + MicroPython + ESP32 + GY-302 测量环境中的光照强度

GY-302是一款基于BH1750FVI光照强度传感器芯片的模块。该模块能够直接测量出环境中的光照强度,并将光照强度转换为数字信号输出。其具体参数如下表所示。 参数名称 参数特性 测量范围 0-65535 LX 测量精度 在环境光下误差小于20%,能够自动忽略50/60…

AJAX和XHR、fetch、axios的关系

AJAX中有两套原生的API,一个是XHR(XMLHttpRequest),一个是Fetch API axios是第三方库,在浏览器环境中使用的是XHR umi-request也是第三方库,在浏览器环境中使用的是Fetch 在 AJAX(Asynchronous JavaScript and XML&am…

openlayers地图缓存添加

//通过安装包localforage(npm install localforage)或https://cdnjs.cloudflare.com/ajax/libs/localforage/1.10.0/localforage.min.js tileCacheStore.js import localforage from localforage var tileCacheStorenull;// 从缓存中获取该瓦片 functio…

云轴科技ZStack出席中国电信国际EMCP平台香港发布会,持续推动海外合作

近日,以“云聚未来 翼起新篇”为主题的中国电信国际多云服务一站式平台(E-surfing Managed Cloud Platform,简称EMCP平台)新闻发布会在香港成功举办,标志着中国电信国际在云计算服务领域取得了又一重大进展。云轴科技…

面试复盘 part 02·1202-1207 日

作品集讲述部分 分析反思 作品集讲述部分,视觉讲述部分需要更换,需要换成其他视觉相关的修改 具体话术 这是一个信息展示优化方案,用户为财务,信息区分度不足,理解成本较高,因此选择需要降低理解成本。…

2024.11.29——[HCTF 2018]WarmUp 1

拿到题&#xff0c;发现是一张图&#xff0c;查看源代码发现了被注释掉的提示 <!-- source.php--> step 1 在url传参看看这个文件&#xff0c;发现了这道题的源码 step 2 开始审计代码&#xff0c;分析关键函数 //mb_strpos($haystack,$needle,$offset,$encoding):int|…

brpc的二次封装以及brpc与etcd的联合

目的&#xff1a; 搭配etcd的注册中心管理能知道谁能提供什么服务&#xff0c;并用rpc进行服务调用 封装思想&#xff1a; 信道管理&#xff0c;将不同服务主机的通信信道管理起来 封装&#xff1a; 1.指定的信道管理类 一个服务通常会有多个节点&#xff0c;每个节点都会…

【提升效率】如何写好一份详细设计文档

版本日期修订人描述V1.02024/12/6nick huang创建文档 背景 CSDN在发起“如何做好一份技术文档”的活动。 想起我最近在写一份详细设计&#xff0c;有一些感受&#xff1a; 一份考虑较周全的“详细设计文档模板”能起到质量保底的作用。 当一名初级技术人员需要编写详细设计文…