news 2026/6/22 9:00:12

详细分析线程池上下文的基本知识(附Demo)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
详细分析线程池上下文的基本知识(附Demo)

目录

  • 前言
  • 1. 基本知识
  • 2. 父子线程数据不同
  • 3. 父子线程数据相同

前言

Java基本知识:

  1. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
  2. 【Java项目】实战CRUD的功能整理(持续更新)

1. 基本知识

本意大概如下:
基于 ThreadLocal 的请求级校验上下文容器(ValidatorDataContext,这是自定义的),用于在同一个请求线程内共享和传递校验/业务相关数据。它继承自ConcurrentHashMap<String, Object>,本质上是一个线程安全的 Key-Value 上下文,但通过 ThreadLocal 绑定到当前线程,从而保证每个请求线程拥有独立的数据副本,互不干扰

整体设计目的是:在校验(Validator)或业务处理链路中,作为一个与请求生命周期一致的上下文数据容器,方便不同校验器或组件在不显式传参的情况下共享数据,同时保证线程安全与请求隔离。

**线程池上下文(Thread Pool Context)**指的是:
在任务提交线程中已有的一些“隐式状态”,如何在被线程池复用的工作线程中继续可用

“隐式状态”通常包括:

登录用户信息(userId、token)
请求信息(requestId、traceId)
租户信息(tenantId)
语言/区域(Locale)
安全上下文(SecurityContext)
日志链路(MDC / Trace)
数据源路由信息
事务标记(⚠️)
线程池上下文的Demo如下:

1️⃣ ThreadLocal 的设计前提
ThreadLocal 的核心假设是:
一个请求 = 一个线程

但在线程池中:
线程是 复用的
一个线程会执行 多个不同请求的任务

➡️ 导致两个问题:

❌ 问题一:上下文丢失

ThreadLocal.set("userA");executor.submit(()->{// 这里读不到 userA});

原因:
任务在线程池的另一个线程执行


❌ 问题二:上下文污染(更危险)

ThreadLocal.set("userA");executor.submit(()->{// 执行完后没清理});executor.submit(()->{// 读到的是 userA(脏数据)});

原因:
线程池线程被复用,上一个任务的 ThreadLocal 没清



线程池的上下文Demo:

package线程池上下文;importlombok.Data;importjava.util.concurrent.ConcurrentHashMap;@DatapublicclassValidatorDataContextextendsConcurrentHashMap<String,Object>{/** * * 请求对象 */publicObjectrequestDto;publicObjectput(Stringkey,Objectvalue){if(key==null||value==null){returnnull;}else{returnsuper.put(key,value);}}/** * * ValidatorContext为请求上下文,与当前请求线程绑定,继承自ConcurrentHashMap */publicstaticfinalThreadLocal<?extendsValidatorDataContext>threadLocal=ThreadLocal.withInitial(()->newValidatorDataContext());/** * * 获取当前线程的上下文 * * @return */publicstaticValidatorDataContextgetCurrentContext(){ValidatorDataContextcontext=threadLocal.get();returncontext;}/** * * 设值 * * @param key * @param value */publicvoidset(Stringkey,Objectvalue){if(value!=null){put(key,value);}else{remove(key);}}/** * 设置值 * @param clazz 会自动取SimpleName为Key * @param value * @author K * 2020年10月12日下午6:38:01 */publicvoidsetByClass(Classclazz,Objectvalue){Stringkey=clazz.getSimpleName();set(key,value);}/** * * 获取String值 * * @param key * @return */publicStringgetString(Stringkey){return(String)get(key);}/**其他类型的值同理,进行强转换*//** * * 获取对象 * * @param <T> * @return */public<T>TgetByClazz(Class<T>clazz){if(get(clazz.getSimpleName())==null){returnnull;}else{return(T)get(clazz.getSimpleName());}}public<T>TgetRequestDto(Class<T>clazz){returnclazz.cast(requestDto);// 强制类型转换,更安全}publicvoidsetRequestDto(ObjectrequestDto){this.requestDto=requestDto;}}

2. 父子线程数据不同

子线程不会拷贝父线程的数据!

package线程池上下文;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.TimeUnit;// 模拟一个业务对象classUser{privateStringname;privateintage;publicUser(Stringname,intage){this.name=name;this.age=age;}publicStringgetName(){returnname;}publicintgetAge(){returnage;}}publicclassValidatorDataContextDemo{publicstaticvoidmain(String[]args)throwsInterruptedException{// 创建线程池ExecutorServiceexecutor=Executors.newFixedThreadPool(2);// === 主线程:设置上下文 ===ValidatorDataContextcontext=ValidatorDataContext.getCurrentContext();context.set("traceId","TRACE-20251225-001");context.setRequestDto(newUser("Alice",30));context.setByClass(User.class,newUser("Bob",25));System.out.println("主线程 - traceId: "+context.getString("traceId"));System.out.println("主线程 - RequestDto name: "+context.getRequestDto(User.class).getName());System.out.println("主线程 - User class value name: "+context.getByClazz(User.class).getName());// === 在线程池中访问上下文 ===executor.submit(()->{// 注意:ThreadLocal 是线程隔离的,所以线程池线程无法直接获取主线程上下文ValidatorDataContextthreadContext=ValidatorDataContext.getCurrentContext();System.out.println("\n子线程1 - traceId: "+threadContext.getString("traceId"));// nullSystem.out.println("子线程1 - RequestDto: "+threadContext.getRequestDto());// null// 可以在子线程独立设置threadContext.set("traceId","THREAD-TRACE-001");System.out.println("子线程1 - 新 traceId: "+threadContext.getString("traceId"));});executor.submit(()->{ValidatorDataContextthreadContext=ValidatorDataContext.getCurrentContext();System.out.println("\n子线程2 - traceId: "+threadContext.getString("traceId"));// null});// 等待线程执行完executor.shutdown();executor.awaitTermination(5,TimeUnit.SECONDS);// === 主线程上下文依然可用 ===System.out.println("\n主线程 - traceId 再次访问: "+context.getString("traceId"));}}

截图如下:

3. 父子线程数据相同

在大的Demo下增加如下:

// 克隆当前上下文publicValidatorDataContextcopy(){ValidatorDataContextcopy=newValidatorDataContext();copy.putAll(this);copy.requestDto=this.requestDto;returncopy;}

总体的Demo测试如下:

package线程池上下文;importjava.util.concurrent.*;// 包装 Runnable,传递上下文classContextAwareRunnableimplementsRunnable{privatefinalRunnabletask;privatefinalValidatorDataContextcapturedContext;publicContextAwareRunnable(Runnabletask,ValidatorDataContextcontext){this.task=task;this.capturedContext=context.copy();// 拷贝上下文}@Overridepublicvoidrun(){ValidatorDataContextprevious=ValidatorDataContext.getCurrentContext();try{// 设置当前线程上下文为捕获的上下文ValidatorDataContext.threadLocal.set(capturedContext);task.run();}finally{// 执行完毕,恢复或清理上下文ValidatorDataContext.threadLocal.set(previous);}}}// 主类 DemopublicclassValidatorDataContextWithThreadPoolDemo{// 辅助方法:包装 RunnableprivatestaticRunnablewrap(Runnabletask){returnnewContextAwareRunnable(task,ValidatorDataContext.getCurrentContext());}publicstaticvoidmain(String[]args)throwsInterruptedException,ExecutionException{ExecutorServiceexecutor=Executors.newFixedThreadPool(2);// 主线程设置上下文ValidatorDataContextcontext=ValidatorDataContext.getCurrentContext();context.set("traceId","TRACE-20251225-001");context.setRequestDto(newUser("Alice",30));context.setByClass(User.class,newUser("Bob",25));System.out.println("主线程 - traceId: "+context.getString("traceId"));System.out.println("主线程 - RequestDto name: "+context.getRequestDto(User.class).getName());System.out.println("主线程 - User class value name: "+context.getByClazz(User.class).getName());// 提交线程池任务(自动继承主线程上下文)Future<?>future1=executor.submit(wrap(()->{ValidatorDataContextthreadContext=ValidatorDataContext.getCurrentContext();System.out.println("\n子线程1 - traceId: "+threadContext.getString("traceId"));System.out.println("子线程1 - RequestDto name: "+threadContext.getRequestDto(User.class).getName());System.out.println("子线程1 - User class value name: "+threadContext.getByClazz(User.class).getName());// 修改上下文不会影响主线程threadContext.set("traceId","THREAD-TRACE-001");}));Future<?>future2=executor.submit(wrap(()->{ValidatorDataContextthreadContext=ValidatorDataContext.getCurrentContext();System.out.println("\n子线程2 - traceId: "+threadContext.getString("traceId"));}));// 等待执行完成future1.get();future2.get();// 主线程上下文仍然保持原值System.out.println("\n主线程 - traceId 再次访问: "+context.getString("traceId"));executor.shutdown();executor.awaitTermination(5,TimeUnit.SECONDS);}}

截图如下:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/20 6:08:08

需求接口人与研发接口人的职责分别是什么

需求接口人与研发接口人是连接“业务价值”与“技术实现”的两个核心枢纽。需求接口人&#xff08;通常是产品经理或业务分析师&#xff09;的核心职责是“定义”&#xff0c;即明确“做什么”和“为什么做”&#xff0c;他们对业务价值、需求优先级和用户体验负责。研发接口人…

作者头像 李华
网站建设 2026/6/20 17:21:52

基于大数据的短视频用户兴趣分析的设计与实现(程序+文档+讲解)

课题介绍在短视频平台精细化运营、个性化推荐需求下&#xff0c;传统用户兴趣分析存在 “维度单一、实时性差、精准度不足” 的痛点&#xff0c;基于大数据技术构建的短视频用户兴趣分析体系&#xff0c;整合用户行为数据、内容交互数据、环境数据等多源信息&#xff0c;实现用…

作者头像 李华
网站建设 2026/6/16 2:24:49

【最新2023】各省地区生产总值GDP 人均生产总值(人均GDP) 地区生产总值指数的 省级省份

【最新2023】各省地区生产总值GDP 人均生产总值(人均GDP) 地区生产总值指数的 省级省份 时间范围1999-2023年 人均生产总值指数(人均GDP指数) 包括一下: 人均生产总值(人均GDP) 各省地区生产总值GDP 人均生产总值指数(人均GDP指数) 地区生产总值指数 见图 说明:人均生产总值指…

作者头像 李华
网站建设 2026/6/22 3:38:44

医疗自动标注漏医生隐写症状 后来补NLP规则引擎才救回诊断准确率

&#x1f4dd; 博客主页&#xff1a;jaxzheng的CSDN主页 目录医疗数据科学&#xff1a;当Excel遇上心电图&#xff0c;我差点把医院整崩溃了 一、为什么说我是"数据界的急诊科医生" 二、那些年我在医疗数据里踩过的坑 三、那些让人拍案叫绝的医疗数据应用 四、给想入…

作者头像 李华
网站建设 2026/6/20 7:33:25

C 语言字符串函数超全解析

对于刚接触 C 语言的小伙伴来说&#xff0c;字符串函数就像 “字符处理的万能工具”&#xff0c;但用不好也容易踩坑。这篇内容会从 “核心逻辑→常用函数→避坑指南” 一步步讲&#xff0c;先懂底层、再学用法、最后避坑&#xff0c;保证通俗易懂&#xff5e; 一、先搞懂&…

作者头像 李华
网站建设 2026/6/20 5:28:53

海外仓签收入库环节怎么优化?海外仓入库流程优化方案(附TOPWMS实操)

在海外仓一件代发业务中&#xff0c;海外仓入库环节常被低估&#xff0c;但入库的问题直接影响到后续仓库的一系列操作。货物堆堵、SKU混乱、错发追责等入库乱象&#xff0c;并非单纯的管理疏忽&#xff0c;其根源在于缺乏一套系统化、标准化的流程管控体系。今天将根据我们的东…

作者头像 李华