李锋镝的博客

  • 首页
  • 时间轴
  • 说说
  • 读书观影
  • 系列
  • AI工具集
  • 论坛
  • 友圈
    • 友链
    • 朋友圈
    • 游客中心
  • 留言
    • 留言
    • 走心评论
  • 关于
    • 关于本站
    • Now
    • 每日心情
    • 网站地图
    • 网站统计
    • 赞助
  • 星球穿梭
  • 🚇开往
静亦定 动亦定
惟坚韧者始能遂其志
  1. 首页
  2. 原创
  3. 技术
  4. 正文

TransmittableThreadLocal介绍与使用

2025年6月3日 244 1 0
本文最后更新于 2025年6月3日,距今已 521 天,其中的信息可能已经发生变化,请注意甄别。

TransmittableThreadLocal(TTL)是阿里巴巴开源的一个 Java 库,用于解决 线程池环境下 ThreadLocal 上下文丢失 的问题。它是 InheritableThreadLocal 的增强版,特别适用于异步编程、分布式系统等场景。以下是详细解析:

一、核心问题:为什么需要 TransmittableThreadLocal?

1. 传统 ThreadLocal 的局限性

  • 线程隔离性:ThreadLocal 为每个线程提供独立的变量副本,子线程无法获取父线程的 ThreadLocal 值。
  • 线程池复用问题:线程池中的线程会被复用,InheritableThreadLocal 仅在创建子线程时复制一次值,后续任务无法获取最新的父线程上下文。

示例场景:

// 主线程设置 InheritableThreadLocal
InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
threadLocal.set("parent-value");

// 提交任务到线程池(线程复用导致上下文不更新)
ExecutorService executor = Executors.newFixedThreadPool(1);
for (int i = 0; i < 3; i++) {
    threadLocal.set("value-" + i);
    executor.submit(() -> {
        System.out.println(threadLocal.get()); // 输出固定值 "value-0"(线程池复用同一个线程)
    });
}

2. TTL 的解决方案

TransmittableThreadLocal 通过 捕获-传递-恢复 机制,确保:

  • 子线程执行时能获取父线程 最新 的上下文值。
  • 即使在线程池环境下,每次任务执行时上下文都能正确传递。

二、TransmittableThreadLocal 的工作原理

1. 核心机制

  • 捕获(Capture):在提交任务时,记录当前线程的 TransmittableThreadLocal 值。
  • 传递(Transmit):将捕获的值传递给执行任务的线程。
  • 恢复(Restore):任务执行前后,分别恢复和还原上下文,避免线程污染。

2. 关键类与方法

  • TransmittableThreadLocal<T>:继承自 ThreadLocal,扩展了上下文传递能力。
  • TtlRunnable/TtlCallable:包装 Runnable/Callable,自动处理上下文传递。
  • TtlExecutors:工具类,用于包装线程池(如 ExecutorService)。

三、使用示例

1. 基础用法

import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.TtlRunnable;

public class TTLExample {
    // 创建 TTL 实例
    private static final TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(1);

        // 主线程设置上下文
        context.set("main-value");

        // 包装任务,自动传递上下文
        Runnable task = TtlRunnable.get(() -> {
            System.out.println("Task 1: " + context.get()); // 输出: "main-value"
        });

        executor.submit(task);

        // 更新上下文
        context.set("updated-value");

        // 提交另一个任务
        executor.submit(TtlRunnable.get(() -> {
            System.out.println("Task 2: " + context.get()); // 输出: "updated-value"(正确获取最新值)
        }));

        executor.shutdown();
    }
}

2. 包装线程池

// 包装线程池,自动处理所有提交的任务
ExecutorService executor = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(2));

// 直接提交任务,无需手动包装
executor.submit(() -> {
    System.out.println("Task in wrapped executor: " + context.get());
});

3. 与异步框架集成

// CompletableFuture 结合 TTL
CompletableFuture.runAsync(
    TtlRunnable.get(() -> { /* 任务逻辑 */ }),
    executor
);

// RxJava 结合 TTL
Observable.just("data")
    .subscribeOn(Schedulers.from(executor))
    .doOnNext(data -> {
        // 此处可获取主线程的上下文
    });

四、高级特性

1. 自定义传播规则

通过 Transmitter 接口自定义上下文的捕获、传递和恢复逻辑:

TransmittableThreadLocal<String> ttl = new TransmittableThreadLocal<String>() {
    @Override
    protected String copy(String parentValue) {
        // 自定义复制逻辑(如深拷贝)
        return parentValue != null ? new String(parentValue) : null;
    }
};

2. 上下文清除

使用 ClearTtlValueFilter 自动清除不需要传递的上下文:

// 注册过滤器,清除某些 TTL 值
public class MyClearFilter implements ClearTtlValueFilter {
    @Override
    public boolean clear(Object value) {
        return value instanceof SensitiveData; // 清除敏感数据
    }
}

// 全局注册过滤器
TtlFilters.registerClearTtlValueFilter(new MyClearFilter());

五、适用场景

场景 说明
分布式链路追踪 传递 TraceID、SpanID 等上下文,确保跨线程调用的追踪连续性。
用户会话管理 在异步任务中保持用户认证信息(如 Session、JWT)。
多租户系统 传递租户 ID,确保子线程正确访问租户数据。
事务上下文 在异步事务中传递 Transaction ID 或隔离级别。
日志 MDC(Mapped Diagnostic Context) 传递日志上下文(如请求 ID),便于日志聚合和分析。

六、与其他方案的对比

方案 优点 缺点 适用场景
ThreadLocal 简单,线程隔离 不支持跨线程传递 单线程上下文存储
InheritableThreadLocal 支持父子线程传递 线程池环境下上下文不更新 固定线程创建场景(非线程池)
手动传递上下文 完全可控,无依赖 代码侵入性强,需修改所有方法签名 小规模项目或简单场景
TransmittableThreadLocal 零代码侵入,支持线程池和异步框架 需引入依赖,有一定性能开销 复杂异步系统、分布式应用

七、注意事项

  1. 性能开销:TTL 会增加每次任务提交和执行的开销(约 10-20%),对性能敏感的系统需谨慎评估。
  2. 内存泄漏风险:若存储大对象且未及时清理,可能导致内存泄漏,建议配合 try-finally 手动清除。
  3. 兼容性:与部分框架(如 Hystrix)集成时需额外配置,可能需要自定义传播器。
  4. 版本依赖:推荐使用最新版本(如 2.14.2+),修复了多个已知问题。

八、总结

TransmittableThreadLocal 是解决 异步编程中上下文传递问题 的利器,特别适合复杂的分布式系统和线程池环境。通过简单的包装,即可实现透明的上下文传播,避免手动传递的代码冗余和错误风险。在高并发场景下,需权衡性能开销,必要时结合异步框架的原生上下文机制(如 Reactor 的 Context)使用。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
分享到

TransmittableThreadLocal介绍与使用

也可使用浏览器菜单中的「分享」功能

微信扫一扫分享

标签: InheritableThreadLocal JAVA ThreadLocal TransmittableThreadLocal 多线程 线程 线程安全 线程池
最后更新:2025年6月3日

岁月同一天 11 月 6 日

回望过去的今天,你在写什么

  • AI
    1 年前 2025年11月6日
    AI能写代码,却造不出软件:软件工程的核心竞争力从未改变

    “我用AI拼了个Demo,就差上线了,能帮我变成产品吗?” 最近越来越多非技术从业者带着这样的需求找上门——他们可能是律…

  • 代码人生
    1 年前 2025年11月6日
    西蒙学习法实战指南:6个月攻克新领域,从入门到能用的高效路径

    作为IT从业者,我们每天都面临新技术的冲击——今天是AI大模型,明天是云原生,后天是低代码开发。有限的时间与无限的学习需…

  • AI
    1 年前 2025年11月6日
    从Token到计费:大模型背后的文本编码逻辑与商业本质

    你是否有过这样的困惑?——给大模型发一段500字的中文需求,却被扣除了800多个Token;同样一篇文章,在GPT-4中…

  • 6 年前 2020年11月6日
    8条经验轻松上手IDEA插件开发

    IDEA作为我们(后端Java开发者)必不可少的IDE,以其智能的代码提示、多样的框架支持、简洁的开发界面等特性,被业界…

  • 其他
    7 年前 2019年11月6日
    架构师究竟比高级开发厉害在哪?

    目前我在互联网公司里干了1年多,接触了多位技术和业务的架构师,由于我正在升级到架构师,所以能直观地感受到高级开发和架构的…

  • 转载
    7 年前 2019年11月6日
    如何在面试中介绍自己的项目经验

    在面试时,经过寒暄后,一般面试官会让介绍项目经验 。常见的问法是,说下你最近的(或最拿得出手的)一个项目。 根据我们的面…

相关文章
  • 金融级JVM深度调优实战的经验和技巧2025年5月27日
  • 分布式ID生成算法SnowFlake(雪花算法)Java源码2019年7月5日
  • ConcurrentHashMap常用方法源码解析(jdk1.8)2019年10月10日
  • 是时候优雅的和NullPointException说再见了2022年7月15日
  • Spring Boot 配置加载优先级总结2026年8月6日

李锋镝

既然选择了远方,便只顾风雨兼程。

打赏 点赞
< 上一篇
下一篇 >
1234567891112131415161718192021222324252627282930313233343536373839404142434446474849505152535455575859606162636465666769727476777879808182858687909293949596979899
取消回复
…

文章评论

还没有评论,快来抢沙发吧~

绿蚁新醅酒,红泥小火炉。晚来天欲雪,能饮一杯无?

听点儿音乐吧 朋友~
文章目录
最新 热点 随机
最新 热点 随机
给服务器加了WAF 又一个逆天改命的人:小小徐 AI的生成能力等于生产力吗? NGINX严重漏洞(CVE-2026-15176、CVE-2026-93479、CVE-2026-97205) Kratos-plus v1.1.27更新说明 php2shell远程执行漏洞修复(CVE-2026-109618 和 CVE-2026-109619)
给主题增加了游客中心功能心气没了,干什么都不得劲我觉得是时候公布我的导航网站了游本昌去世关于主题加载速度优化的一点儿小演进给主题增加了Now、每日心情、年度回顾、岁月同一天、随机漫步等功能
Navicat Premium数据库账号密码解密 从Token到计费:大模型背后的文本编码逻辑与商业本质 用动画解释 TCP 三次握手过程 10 个MQ高频业务场景深度解析 分布式ID生成算法SnowFlake(雪花算法)Java源码 推荐一款比较养眼的Xshell配色方案
最近评论
Hary 发布于 18 小时前(11月05日) 前几天看博友发的宝塔防火墙不就是一坨吗,还是算了。这WAF是可以直接部署在网站同一台服务器么
李锋镝 发布于 1 天前(11月05日) 感谢来访,祝越来越好~
李锋镝 发布于 1 天前(11月05日) 应该就是请求太频繁了,我看看合并一下静态资源这些
不凡 发布于 1 天前(11月05日) 我打开这篇文章时,看到评论列表中的操作系统图标、浏览器图标和国家图标这三个都挂了,楼下的头像也挂了,...
李锋镝 发布于 1 天前(11月05日) 触发CC防护了 我把限制改大一些
标签聚合
WordPress Redis 日常 IDEA Theme AI编程 多线程 分布式 SQL Claude ElasticSearch Spring K8s MySQL 架构 AI JAVA 数据库 JVM SpringBoot
友情链接
  • 皮皮社
  • lijie blog
  • 九仞之行
  • Serendipity
  • 林羽凡
  • sssr7844的博客
  • 知向前端
  • Honesty
  • 哥斯拉
  • 刘永博客
  • 韩小韩博客
  • 老张博客
  • 韩情脉脉
  • 懋和道人
  • 瓦匠个人小站
  • 彬红茶日记
  • Mr.Sun的博客
  • 志文工作室
  • 搬砖日记

COPYRIGHT © 2016-2026 lifengdi.com. ALL RIGHTS RESERVED.

lifengdi.com 十年之约虫洞

Domain age badge for lifengdi.com

Theme Kratos-plus By Dylan Li

津ICP备2024022503号-3

京公网安备11011502039375号