当前位置:首页 > 科技  > 软件

基于TTL 解决线程池中 ThreadLocal 线程无法共享的问题

来源: 责编: 时间:2024-04-08 17:19:23 142观看
导读在Java的并发编程领域中,ThreadLocal被广泛运用来解决线程安全困境,它巧妙地为每个线程提供独立的变量副本,有效规避了线程间数据共享的问题。不过,在使用线程池时,传递线程局部变量在父子线程之间并非易事。这是因为Threa

在Java的并发编程领域中,ThreadLocal被广泛运用来解决线程安全困境,它巧妙地为每个线程提供独立的变量副本,有效规避了线程间数据共享的问题。NIX28资讯网——每日最新资讯28at.com

不过,在使用线程池时,传递线程局部变量在父子线程之间并非易事。这是因为ThreadLocal的设计初衷仅在于线程内的数据隔离,无法支持跨线程间的数据传递。NIX28资讯网——每日最新资讯28at.com

背景

在基于Java的应用开发领域,尤其是在利用Spring框架、异步处理和微服务架构构建系统时,常常需要在不同线程或服务之间传递用户会话、数据库事务或其他上下文信息。NIX28资讯网——每日最新资讯28at.com

举例来说,在处理用户请求的Web服务中,记录日志是必不可少的一环。这些日志需包含请求的独特标识(如请求ID),这个ID在请求进入服务时生成,并会贯穿整个处理流程,包括可能并发执行的多个子任务或被分配到线程池中不同线程上执行。(在分布式场景中通常会称之为traceId)NIX28资讯网——每日最新资讯28at.com

在这种情况下,使用ThreadLocal来存储请求ID会带来问题:并发执行的子任务无法访问父线程ThreadLocal中存储的请求ID,而且在使用线程池时,线程的重用可能导致请求ID被错误地共享或丢失。NIX28资讯网——每日最新资讯28at.com

伪代码:NIX28资讯网——每日最新资讯28at.com

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadLocalExample {        private static ThreadLocal<String> requestId = new ThreadLocal<>();    public static void main(String[] args) {        requestId.set("12345"); // 设置请求ID        ExecutorService executor = Executors.newFixedThreadPool(2);        executor.submit(() -> {            System.out.println("Child task running in a separate thread: " + requestId.get());        });        executor.shutdown();    }}

在这个示例中,父线程设置了请求ID为"12345",但是当子任务在另一个线程中执行时,无法访问到父线程中的ThreadLocal变量requestId,因此子任务无法获取到请求ID,可能会输出null或者""。NIX28资讯网——每日最新资讯28at.com

伪代码:NIX28资讯网——每日最新资讯28at.com

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadLocalThreadPoolExample {        private static ThreadLocal<String> requestId = new ThreadLocal<>();    public static void main(String[] args) {        requestId.set("12345"); // 设置请求ID        ExecutorService executor = Executors.newFixedThreadPool(2);        executor.submit(() -> {            System.out.println("Child task running in a thread pool: " + requestId.get());        });        // 另一个任务复用线程        executor.submit(() -> {            System.out.println("Another child task running in the same thread: " + requestId.get());        });        executor.shutdown();    }}

在这个示例中,如果线程池中的两个任务在同一个线程中执行,且没有正确处理ThreadLocal变量,可能会导致第二个任务获取到了第一个任务的请求ID,导致请求ID的错误共享。NIX28资讯网——每日最新资讯28at.com

技术选型

为了应对这一难题,可以采用TransmittableThreadLocal(TTL)这一阿里巴巴开源工具库,专为解决在使用线程池等会重用线程的情况下,ThreadLocal无法正确管理线程上下文的问题而设计。NIX28资讯网——每日最新资讯28at.com

GitHub开源地址:https://github.com/alibaba/transmittable-thread-localNIX28资讯网——每日最新资讯28at.com

TransmittableThreadLocal基于ThreadLocal进行扩展,提供了跨线程传递数据的能力,确保父线程传递值给子线程,并支持线程池等场景下的线程数据隔离。NIX28资讯网——每日最新资讯28at.com

此外,还有JDK自带的InheritableThreadLocal,用于主子线程间参数传递。然而,这种方式存在一个限制:必须在主线程手动创建子线程才可使用,而在线程池中则难以实现此种传递机制。NIX28资讯网——每日最新资讯28at.com

具体实现

依赖引入

首先,需在项目中引入TransmittableThreadLocal的依赖。若为Maven项目,可添加以下依赖:NIX28资讯网——每日最新资讯28at.com

<dependency>  <groupId>com.alibaba</groupId>  <artifactId>transmittable-thread-local</artifactId>  <version><!-- 使用最新版本 --></version> </dependency>

使用TransmittableThreadLocal存储请求ID

public class RequestContext {    // 使用TransmittableThreadLocal来存储请求ID    private static final ThreadLocal<String> requestIdTL = new TransmittableThreadLocal<>();    public static void setRequestId(String requestId) {        requestIdTL.set(requestId);    }    public static String getRequestId() {        return requestIdTL.get();    }    public static void clear() {        requestIdTL.remove();    }}
创建一个线程池,并使用TTL提供的工具类确保线程池兼容TransmittableThreadLocal
import com.alibaba.ttl.threadpool.TtlExecutors;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadPoolUtil {    private static final ExecutorService pool = Executors.newFixedThreadPool(10);    // 使用TtlExecutors工具类包装原始的线程池,使其兼容TransmittableThreadLocal    public static final ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(pool);    public static ExecutorService getExecutorService() {        return ttlExecutorService;    }}

TtlExecutors是TransmittableThreadLocal(TTL)库中的一款实用工具类,其机制在于对Java标准库中的ExecutorService、ScheduledExecutorService等线程池接口的实例进行包装。NIX28资讯网——每日最新资讯28at.com

通过这种封装,确保在使用线程池时,能够正确地传递TransmittableThreadLocal中存储的上下文数据,即使任务在不同线程中执行。这对于解决在使用线程池时ThreadLocal变量值传递的问题至关重要。NIX28资讯网——每日最新资讯28at.com

执行并行任务,并在任务中使用RequestContext来访问请求ID
import java.util.stream.IntStream;public class Application {    public static void main(String[] args) {        // 模拟Web应用中为每个请求设置唯一的请求ID        String requestId = "REQ-" + System.nanoTime();        RequestContext.setRequestId(requestId);        try {            ExecutorService executorService = ThreadPoolUtil.getExecutorService();            IntStream.range(0, 5).forEach(i ->                 executorService.submit(() -> {                    // 在子线程中获取并打印请求ID                    System.out.println("Task " + i + " running in thread " + Thread.currentThread().getName() + " with Request ID: " + RequestContext.getRequestId());                })            );        } finally {            // 清理资源            RequestContext.clear();            ThreadPoolUtil.getExecutorService().shutdown();        }    }}


NIX28资讯网——每日最新资讯28at.com

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-82037-0.html基于TTL 解决线程池中 ThreadLocal 线程无法共享的问题

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 超越GPT4的Agent,我用代码实现了!

下一篇: Go 哪里没有做好?Rob Pike 深刻反思了

标签:
  • 热门焦点
  • Redmi Pad评测:红米充满野心的一次尝试

    Redmi Pad评测:红米充满野心的一次尝试

    从Note系列到K系列,从蓝牙耳机到笔记本电脑,红米不知不觉之间也已经形成了自己颇有竞争力的产品体系,在中端和次旗舰市场上甚至要比小米新机的表现来得更好,正所谓“大丈夫生居
  • 容量越大越不坏?24万块硬盘故障率报告公布 这些产品零故障

    容量越大越不坏?24万块硬盘故障率报告公布 这些产品零故障

    8月5日消息,云存储服务商Backblaze发布了最新的硬盘故障率报告,年故障率有所上升。Backblaze发布的硬盘季度统计数据,其中包括故障率等重要方面。这些结
  • 三言两语说透设计模式的艺术-简单工厂模式

    三言两语说透设计模式的艺术-简单工厂模式

    一、写在前面工厂模式是最常见的一种创建型设计模式,通常说的工厂模式指的是工厂方法模式,是使用频率最高的工厂模式。简单工厂模式又称为静态工厂方法模式,不属于GoF 23种设计
  • 让我们一起聊聊文件的操作

    让我们一起聊聊文件的操作

    文件【1】文件是什么?文件是保存数据的地方,是数据源的一种,比如大家经常使用的word文档、txt文件、excel文件、jpg文件...都是文件。文件最主要的作用就是保存数据,它既可以保
  • 只需五步,使用start.spring.io快速入门Spring编程

    只需五步,使用start.spring.io快速入门Spring编程

    步骤1打开https://start.spring.io/,按照屏幕截图中的内容创建项目,添加 Spring Web 依赖项,并单击“生成”按钮下载 .zip 文件,为下一步做准备。请在进入步骤2之前进行解压。图
  • “又被陈思诚骗了”

    “又被陈思诚骗了”

    作者|张思齐 出品|众面(ID:ZhongMian_ZM)如今的国产悬疑电影,成了陈思诚的天下。最近大爆电影《消失的她》票房突破30亿断层夺魁暑期档,陈思诚再度风头无两。你可以说陈思诚的
  • 签约井川里予、何丹彤,单视频点赞近千万,MCN黑马永恒文希快速崛起!

    签约井川里予、何丹彤,单视频点赞近千万,MCN黑马永恒文希快速崛起!

    来源:视听观察永恒文希传媒作为一家MCN公司,说起它的名字来,可能大家会觉得有点儿陌生,但是说出来下面一串的名字之后,或许大家就会感到震惊,原来这么多网红,都签约这家公司了。根
  • 华为Mate60系列模具曝光:采用硕大圆形后置相机模组+拼接配色方案

    华为Mate60系列模具曝光:采用硕大圆形后置相机模组+拼接配色方案

    据此前多方爆料,今年华为将开始恢复一年双旗舰战略,除上半年推出的P60系列外,往年下半年的Mate系列也将迎来更新,有望在9-10月份带来全新的华为Mate60
  • 2纳米决战2025

    2纳米决战2025

    集微网报道 从三强争霸到四雄逐鹿,2nm的厮杀声已然隐约传来。无论是老牌劲旅台积电、三星,还是誓言重回先进制程领先地位的英特尔,甚至初成立不久的新
Top
Baidu
map