手机餐饮网站开发dw网页制作模板下载

张小明 2026/1/19 22:27:00
手机餐饮网站开发,dw网页制作模板下载,南宁网站建设公司业绩,成都网站制作-中国互联前言在日常开发中#xff0c;我们经常会遇到需要在父子线程之间传递数据的场景。比如用户身份信息、请求ID、链路追踪ID等。ThreadLocal作为Java中重要的线程本地变量机制#xff0c;为我们提供了在单个线程内存储数据的便利。但是#xff0c;当涉及到父子线程之间的数据传递…前言在日常开发中我们经常会遇到需要在父子线程之间传递数据的场景。比如用户身份信息、请求ID、链路追踪ID等。ThreadLocal作为Java中重要的线程本地变量机制为我们提供了在单个线程内存储数据的便利。但是当涉及到父子线程之间的数据传递时ThreadLocal默认的行为并不能满足我们的需求。本文将介绍在SpringBoot应用中实现ThreadLocal父子线程传值的几种方式。ThreadLocal 基础回顾首先让我们简单回顾一下ThreadLocal的基本原理java public class ThreadLocalT { // 每个线程都有自己独立的ThreadLocalMap public void set(T value) { Thread t Thread.currentThread(); ThreadLocalMap map getMap(t); if (map ! null) map.set(this, value); else createMap(t, value); } public T get() { Thread t Thread.currentThread(); ThreadLocalMap map getMap(t); if (map ! null) { ThreadLocalMap.Entry e map.getEntry(this); if (e ! null) { SuppressWarnings(unchecked) T result (T)e.value; return result; } } return setInitialValue(); } }ThreadLocal的核心思想是为每个线程维护一个独立的ThreadLocalMap从而实现线程隔离。问题的提出让我们通过一个简单的例子来看看ThreadLocal在父子线程中的默认行为java public class ThreadLocalDemo { private static ThreadLocalString threadLocal new ThreadLocal(); public static void main(String[] args) { threadLocal.set(主线程的值); System.out.println(主线程获取: threadLocal.get()); // 输出: 主线程的值 Thread childThread new Thread(() - { System.out.println(子线程获取: threadLocal.get()); // 输出: null }); childThread.start(); } }从上面的例子可以看出子线程无法访问父线程中设置的ThreadLocal值。这是因为每个线程都有自己独立的ThreadLocalMap。解决方案一InheritableThreadLocalJava为我们提供了InheritableThreadLocal来解决父子线程传值的问题java public class InheritableThreadLocalDemo { private static InheritableThreadLocalString inheritableThreadLocal new InheritableThreadLocal(); public static void main(String[] args) { inheritableThreadLocal.set(主线程的值); System.out.println(主线程获取: inheritableThreadLocal.get()); Thread childThread new Thread(() - { System.out.println(子线程获取: inheritableThreadLocal.get()); // 输出: 主线程的值 }); childThread.start(); } }InheritableThreadLocal 原理分析InheritableThreadLocal的实现在Thread类中java public class Thread implements Runnable { // 父线程的inheritableThreadLocals会在创建子线程时复制 private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { // ... if (inheritThreadLocals parent.inheritableThreadLocals ! null) this.inheritableThreadLocals ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); // ... } }InheritableThreadLocal 的局限性1. 时机限制只在创建线程时进行值传递后续修改不会传递到已创建的子线程2. 线程池问题在线程池中使用时由于线程会被复用可能导致数据混乱解决方案二使用TransmittableThreadLocal阿里巴巴开源的TransmittableThreadLocalTTL是解决线程池场景下父子线程传值问题的优秀方案添加依赖xml dependency groupIdcom.alibaba/groupId artifactIdtransmittable-thread-local/artifactId version2.14.5/version /dependency基本使用java import com.alibaba.ttl.TransmittableThreadLocal; import com.alibaba.ttl.threadpool.TtlExecutors; public class TtlDemo { private static TransmittableThreadLocalString ttl new TransmittableThreadLocal(); public static void main(String[] args) { ttl.set(主线程的值); System.out.println(主线程获取: ttl.get()); // 使用TTL装饰的线程池 ExecutorService executor TtlExecutors.getTtlExecutorService( Executors.newFixedThreadPool(2) ); executor.submit(() - { System.out.println(线程池任务1获取: ttl.get()); // 输出: 主线程的值 }); // 修改值后提交新任务 ttl.set(更新后的值); executor.submit(() - { System.out.println(线程池任务2获取: ttl.get()); // 输出: 更新后的值 }); } }TTL 与Spring Boot的集成在Spring Boot应用中我们可以通过以下方式集成TTL1. 配置TTL异步执行器java Configuration EnableAsync public class AsyncConfig implements AsyncConfigurer { Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(100); executor.setThreadNamePrefix(Async-); // 使用TTL装饰 return TtlExecutors.getTtlExecutor(executor); } }2. 使用TTL的请求拦截器java Component public class TtlRequestInterceptor implements HandlerInterceptor { private static final TransmittableThreadLocalString requestId new TransmittableThreadLocal(); Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String id UUID.randomUUID().toString(); requestId.set(id); return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { requestId.remove(); // 清理 } public static String getRequestId() { return requestId.get(); } }解决方案三自定义TaskDecoratorSpring提供了TaskDecorator接口允许我们对Runnable任务进行装饰java Configuration EnableAsync public class CustomAsyncConfig implements AsyncConfigurer { Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(100); executor.setThreadNamePrefix(CustomAsync-); // 设置自定义装饰器 executor.setTaskDecorator(new ContextCopyingDecorator()); executor.initialize(); return executor; } private static class ContextCopyingDecorator implements TaskDecorator { Override public Runnable decorate(Runnable runnable) { // 获取父线程的ThreadLocal上下文 MapString, Object context getContextFromCurrentThread(); return () - { try { // 在子线程中复制上下文 setContextToCurrentThread(context); runnable.run(); } finally { clearCurrentThreadContext(); } }; } private MapString, Object getContextFromCurrentThread() { MapString, Object context new HashMap(); // 收集当前线程的ThreadLocal值 // 例如从自定义的ThreadLocal中获取 if (UserContext.getUser() ! null) { context.put(userInfo, UserContext.getUser()); } if (RequestContextHolder.getRequestAttributes() ! null) { context.put(requestAttributes, RequestContextHolder.getRequestAttributes()); } return context; } private void setContextToCurrentThread(MapString, Object context) { // 在子线程中设置上下文 if (context.containsKey(userInfo)) { UserContext.setUser((UserContext.UserInfo) context.get(userInfo)); } if (context.containsKey(requestAttributes)) { RequestContextHolder.setRequestAttributes((RequestAttributes) context.get(requestAttributes)); } } private void clearCurrentThreadContext() { // 清理上下文防止内存泄漏 UserContext.clear(); RequestContextHolder.resetRequestAttributes(); } } }解决方案四使用Spring的RequestContextHolder在Spring Web应用中我们可以利用RequestContextHolder来传递请求上下文java Service public class ContextService { Async public CompletableFutureString asyncMethod() { // 获取父线程的请求上下文 RequestAttributes attributes RequestContextHolder.getRequestAttributes(); return CompletableFuture.supplyAsync(() - { // 在异步线程中设置上下文 RequestContextHolder.setRequestAttributes(attributes); try { // 执行业务逻辑 String result doSomeWork(); return result; } finally { RequestContextHolder.resetRequestAttributes(); } }); } private String doSomeWork() { // 获取请求相关的信息 HttpServletRequest request ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); return 处理完成: request.getRequestURI(); } }方案选择建议基于上述性能对比和适用场景我们可以给出以下选择建议1. 简单的父子线程传值使用InheritableThreadLocal2. 线程池场景推荐使用TransmittableThreadLocal3. Spring异步任务使用TaskDecorator4. Web应用请求上下文使用RequestContextHolder最佳实践1. 内存泄漏预防无论使用哪种方案都要注意及时清理ThreadLocaljava public class SafeThreadLocalUsage { private static ThreadLocalObject threadLocal new ThreadLocal(); public void doWork() { try { threadLocal.set(someValue); // 业务逻辑 } finally { threadLocal.remove(); // 防止内存泄漏 } } }2. 上下文封装建议封装一个统一的上下文管理器java public class UserContext { private static final ThreadLocalUserInfo USER_CONTEXT new TransmittableThreadLocal(); public static void setUser(UserInfo user) { USER_CONTEXT.set(user); } public static UserInfo getUser() { return USER_CONTEXT.get(); } public static void clear() { USER_CONTEXT.remove(); } public static class UserInfo { private String userId; private String userName; private String requestId; // getters and setters } }3. 拦截器统一管理java Component public class UserContextInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { UserInfo userInfo buildUserInfo(request); UserContext.setUser(userInfo); return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { UserContext.clear(); } private UserInfo buildUserInfo(HttpServletRequest request) { UserInfo userInfo new UserInfo(); userInfo.setUserId(request.getHeader(X-User-Id)); userInfo.setRequestId(UUID.randomUUID().toString()); return userInfo; } }总结本文介绍了四种在SpringBoot中实现ThreadLocal父子线程传值的方案1. InheritableThreadLocal最简单的原生解决方案适用于基础场景2. TransmittableThreadLocal功能强大的第三方解决方案特别适合线程池场景3. TaskDecoratorSpring提供的优雅解决方案集成度高4. RequestContextHolderSpring Web应用的内置方案在实际项目中我们应该根据具体的业务场景和技术栈选择合适的方案。同时要注意内存管理和上下文清理确保系统的稳定性和性能。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

中文响应式网站模板电商会学着做网站呢

告别平台切换烦恼!OBS多平台推流插件一键同步直播全攻略 【免费下载链接】obs-multi-rtmp OBS複数サイト同時配信プラグイン 项目地址: https://gitcode.com/gh_mirrors/ob/obs-multi-rtmp 还在为不同平台的直播设置而头疼吗?想要同时覆盖抖音、B…

张小明 2026/1/17 22:20:37 网站建设

网站服务器和空间有什么区别应用下载app排行榜

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个基于GoView的AI辅助数据可视化平台。主要功能:1.支持用户通过自然语言描述需求(如展示近半年销售额的柱状图)2.AI自动解析并生成对应的E…

张小明 2026/1/17 22:20:37 网站建设

营销型网站建设设计网亿(深圳)信息科技有限公司

高级模型/视图编程:表格数据树状表示 在数据库等场景中,当列具有同质数据类型时,通用委托具有三个关键优势: 1. 易于更改委托 :可以轻松更改特定列使用的委托,若模型增加列,还能添加额外的列委托。 2. 避免代码重复 :使用列委托可避免创建大量特定于模型的自定义…

张小明 2026/1/17 22:20:38 网站建设

门户网站建设经验总结报告凡客诚品售后服务有哪些

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…

张小明 2026/1/17 22:20:39 网站建设

佛山高端网站建设公司wordpress特殊插件

AI编程助手深度定制完全指南 【免费下载链接】awesome-cursorrules 📄 A curated list of awesome .cursorrules files 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-cursorrules 在当今快速迭代的软件开发环境中,一个能够精准理解…

张小明 2026/1/19 20:39:06 网站建设

安徽网站建设认准-晨飞网络怎么给客户推网站建设

第一章:Open-AutoGLM是什么技术 Open-AutoGLM 是一种面向自动化自然语言处理任务的开源技术框架,专注于增强大语言模型在复杂推理与多步骤任务中的表现。该技术融合了图神经网络(GNN)与提示工程(Prompt Engineering&am…

张小明 2026/1/17 22:20:41 网站建设