线程之间如何传递上下文信息

news2024/12/27 17:20:48

文章目录

  • 源码
  • 解读
    • 1. 扩展ThreadPoolExecutor
    • 2. 扩展Runnable
    • 3. 整体流程

源于工作中一个业务场景的需求。

源码

话不多说,先贴完整的源码:

public class ContextPassingBetweenThread {
    private static ThreadLocal<String> CONTEXT = new ThreadLocal<>();
    private static ExecutorService executor = new ThreadPoolExecutor(1, 1,
            60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(512));

    private static ExecutorService executorWrap = new ThreadPoolExecutorWrap(1, 1,
            60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(512));
	/**
  	 * 编码时可以把下面三个静态内部类拎出去,放这里方便解释
  	 */
    static class ThreadPoolExecutorWrap extends ThreadPoolExecutor {
        public ThreadPoolExecutorWrap(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }

        @Override
        public Future<?> submit(Runnable task) {
            if (task == null) {
                throw new NullPointerException();
            }
            RunnableFuture<Void> ftask = newTaskFor(new RunnableWrap(task), null);
            execute(ftask);
            return ftask;
        }
		
		@Override
        public <T> Future<T> submit(Callable<T> task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<T> ftask = newTaskFor(new CallableWrap(task));
            execute(ftask);
            return ftask;
        }


    }

    static class RunnableWrap implements Runnable {
        private String contextValue;
        private Runnable task;

        public RunnableWrap(Runnable task) {
          	// 注意此处用属性先保存上下文的内容,应为到另一个线程里面调用get方法,
          	// 那么会是其他线程上下文,所以需要一个东西暂时存储
            this.contextValue = CONTEXT.get();
            this.task = task;
        }

        @Override
        public void run() {
            try {
                CONTEXT.set(contextValue);
                // 用户任务逻辑
                task.run();
            } finally {
                CONTEXT.remove();
            }
        }
    }

    static class CallableWrap<V> implements Callable<V>{
        private String contextValue;
        private Callable<V> task;

        public CallableWrap(Callable<V> task) {
            this.contextValue = CONTEXT.get();
            this.task = task;
        }

        @Override
        public V call() throws Exception {
            V call = null;
            try {
                CONTEXT.set(contextValue);
                call = task.call();
            } finally {
                CONTEXT.remove();
            }
            return call;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CONTEXT.set("main context");

        // 方式1:在用户任务中直接进行手动获取/设置上下文逻辑
        executor.submit(new RunnableWrap(() -> System.out.println("hello world: " + CONTEXT.get())));

        // 方式2:自定义线程池,封装成支持保存/设置上下文的任务
        // 无返回值
        executorWrap.submit(() -> System.out.println("hello world: " + CONTEXT.get()));
        // 有返回值
        Future<String> submit = executorWrap.submit(() -> "hello" + CONTEXT.get());
        System.out.println(submit.get());
    }
}

解读

1. 扩展ThreadPoolExecutor

code
改动点:对提交的Runnable以及Callable进行包装,下面就看它们是如何封装的。

2. 扩展Runnable

code
重点关注上面那一段注释,构造方法是调用线程执行的,所以使用ThreadLocal去存储的话,最终是写入到调用线程上下文中的。
run方法的执行代表新的线程已经产生,不清楚的可以看之前的博客,然后新的线程又持有Runnable对象的引用,所以可以取到存储的contextValue,放入到当前线程的上下文,实现上下文在线程之间传递。

Callable与之类似不再赘述。

3. 整体流程

流程

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

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

相关文章

倍福嵌入式PLC开发团队建设

倍福嵌入式PLC开发工程师确实比较难找&#xff0c;这是因为这个领域需要具备丰富的专业知识和技能&#xff0c;而且经验越丰富的工程师越难找到。以下是一些可能导致倍福嵌入式PLC开发工程师难找的原因&#xff1a; 具备相关技能的工程师数量相对较少&#xff1a;嵌入式PLC开发…

Linux平台建立GB28181设备模拟器

目录 下载模拟器解决动态库缺少问题运行模拟器抓包参考资料 在没有GB28181摄像机的情况下,在Linux虚拟机中模拟出一台GB28181摄像机用于调试和学习. 下载模拟器 到网站下载Linux 平台版本: https://www.happytimesoft.com/download.html tar -zxvf happytime-gb28181-device…

Python简介-Python入门到精通

Python的创始人为荷兰人吉多范罗苏姆&#xff08;Guido van Rossum&#xff09;。1989年圣诞节期间&#xff0c;在阿姆斯特丹&#xff0c;Guido为了打发圣诞节的无趣&#xff0c;决心开发一个新的脚本解释程序&#xff0c;作为ABC语言的一种继承。之所以选中Python&#xff08;…

Python中元组解构的技巧

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python中&#xff0c;元组&#xff08;tuple&#xff09;是一种常用的数据结构&#xff0c;它可以将多个值组合在一起。元组的解构是一项强大的特性&#xff0c;快速、方便地将元组中的值分配给多个变量。本文…

【电脑技巧】Win11关闭自动更新

要想彻底关闭Windows电脑的自动更新&#xff0c;仅仅从系统设置里面选择暂停更新是完全不够用的&#xff0c;只有将windows自动更新的服务关闭掉&#xff0c;才能有效阻止其更新。 关闭win11电脑自动更新的办法&#xff0c;具体操作如下&#xff1a; 1.在winr运行框中输入servi…

vivado 使用IP Integrator源

使用IP Integrator源 在Vivado Design Suite中&#xff0c;您可以在RTL中添加和管理IP子系统块设计&#xff08;.bd&#xff09;项目或设计。使用Vivado IP集成程序&#xff0c;您可以创建IP子系统块设计。IP集成程序使您能够通过实例化和将Vivado IP目录中的多个IP核互连。可…

运筹说 第56期 | 整数规划的数学模型割平面法

前几章讨论过的线性规划问题的一个共同特点是&#xff1a;最优解的取值可以是分数或者小数。然而&#xff0c;在许多实际问题中&#xff0c;决策者要求最优解必须是整数&#xff0c;例如公交车的车辆数、员工的人数、机器的台数、产品的件数等。那么&#xff0c;我们能否将得到…

Zynq7020 使用 Video Processing Subsystem 实现图像缩放

1、前言 没玩过图像缩放都不好意思说自己玩儿过FPGA&#xff0c;这是CSDN某大佬说过的一句话&#xff0c;鄙人深信不疑。。。 目前市面上主流的FPGA图像缩放方案如下&#xff1a;1&#xff1a;Xilinx的HLS方案&#xff0c;该方案简单&#xff0c;易于实现&#xff0c;但只能用…

【RTOS】快速体验FreeRTOS所有常用API(4)队列

目录 四、队列2.1 概念2.2 创建队列2.3 写队列2.4 读队列2.5 队列集&#xff08;可跳过&#xff09; 四、队列 该部分在上份代码基础上修改得来&#xff0c;代码下载链接&#xff1a; https://wwzr.lanzout.com/iBNAS1l75bvc 密码:7xy2 该代码尽量做到最简&#xff0c;不添加多…

软件技术写作指南

▲ 搜索“大龙谈智能内容”关注公众号▲ James是一位居住在苏格兰的文档工程师。 2023年12月&#xff0c;他写了一个名为《Advent of Technical Writing》的系列文章。从12月1日到12月24日&#xff0c;他每天都会在其中发表一篇关于技术写作的博客文章。现在&#xff0c;该系…

c语言for循环和水仙花

c语言for循环和水仙花 c语言for循环和水仙花 c语言for循环和水仙花一、for循环语句格式二、for循环案例水仙花 一、for循环语句格式 for(初始值&#xff1b;表达式&#xff1b;表达式) { 代码 }int main() {for (int i 0; i < 10; i){printf("%d\n", i);} }二、f…

Python数据分析案例32——财经新闻爬虫和可视化分析

案例背景 很多同学的课程作业都是需要自己爬虫数据然后进行分析&#xff0c;这里提供一个财经新闻的爬虫案例供学习。本案例的全部数据和代码获取可以参考&#xff1a;财经新闻数据 数据来源 新浪财经的新闻网&#xff0c;说实话&#xff0c;他这个网站做成这样就是用来爬虫的…

【docker笔记】DockerFile

DockerFile Docker镜像结构的分层 镜像不是一个单一的文件&#xff0c;而是有多层构成。 容器其实是在镜像的最上面加了一层读写层&#xff0c;在运行容器里做的任何文件改动&#xff0c;都会写到这个读写层。 如果删除了容器&#xff0c;也就是删除了其最上面的读写层&…

解决Qt的release构建下无法进入断点调试的问题

在工作的时候遇到了第三方库只提供release版本的库的情况&#xff0c;我需要在这基础上封装一层自家库&#xff0c;在调试的时候遇到如下问题&#xff0c;但是在Qt环境下&#xff0c;release的库只能在进行release构建和调试。 卡在了一直进不了断点的情况。提示内容如下&#…

苹果手机怎么退出QQ群聊?方法简单,一学就会!

QQ作为中国流行的社交软件之一&#xff0c;被大家广泛使用。有时候&#xff0c;我们可能会不小心加入了一些不需要的群聊&#xff0c;或者发现群聊的内容不再符合您的兴趣。 那么&#xff0c;大家这时候可以考虑退出群聊。怎么退出qq群聊&#xff1f;本文将为大家提供详细的步…

SpringBoot中整合ElasticSearch实现增删改查等操作

场景 SpringBoot中整合ElasticSearch快速入门以及踩坑记录&#xff1a; https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/135599698 在上面进行集成的基础上&#xff0c;实现对ES数据的增删改查等操作。 注&#xff1a; 博客&#xff1a;霸道流氓气质-CSDN博客…

SeaTunnel 海量数据同步工具的使用(连载中……)

一、概述 SeaTunnel 是一个非常易用&#xff0c;高性能、支持实时流式和离线批处理的海量数据处理产品&#xff0c;前身是 WaterDrop &#xff08;中文名&#xff1a;水滴&#xff09;&#xff0c;自 2021年10月12日更名为 SeaTunnel 。2021年12月9日&#xff0c;SeaTunnel 正式…

微服务原理

微服务篇 文章目录 微服务篇SpringCloud常见组件 Nacos篇下载源码导入Nacos源码proto编译protobuf定义安装protoc编译proto 运行Nacos服务服务注册服务注册接口客户端NacosServiceRegistryAutoConfigurationNacosAutoServiceRegistrationNacosServiceRegistryNacosNamingServic…

计算机二级Python基本排序题-序号43(补充)

1. 在一组单词中&#xff0c;查找出所有长度最长的单词&#xff0c;如果给定的一组单词是&#xff1a;“cad” ,“VB”.“Python” ,“MATLAB” , “hel1o” , “world” 则输出结果为&#xff1a;the longest words are: Python MATLAB def proc(strings): …