TransmittableThreadLocal
1、简介
TransmittableThreadLocal 是Alibaba开源的、用于解决 “在使用线程池等会缓存线程的组件情况下传递ThreadLocal” 问题的 InheritableThreadLocal 扩展。若希望 TransmittableThreadLocal 在线程池与主线程间传递,需配合 TtlRunnable 和 TtlCallable 使用。
2、使用场景
下面是几个典型场景例子。
- 分布式跟踪系统
- 应用容器或上层框架跨应用代码给下层SDK传递信息
- 日志收集记录系统上下文
3、源码分析
TransmittableThreadLocal 继承自 InheritableThreadLocal,这样可以在不破坏ThreadLocal 本身的情况下,使得当用户利用 new Thread() 创建线程时仍然可以达到传递InheritableThreadLocal 的目的。
public class TransmittableThreadLocal<T> extends InheritableThreadLocal<T> { ...... }
TransmittableThreadLocal 相比较 InheritableThreadLocal 很关键的一点改进是引入holder变量,这样就不必对外暴露Thread中的 inheritableThreadLocals(参考InheritableThreadLocal详解),保持ThreadLocal.ThreadLocalMap的封装性。
// 理解holder,需注意如下几点:
// 1、holder 是 InheritableThreadLocal 变量;
// 2、holder 是 static 变量;
// 3、value 是 WeakHashMap;
// 4、深刻理解 ThreadLocal 工作原理;
private static InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>> holder =new InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>>() {@Overrideprotected Map<TransmittableThreadLocal<?>, ?> initialValue() {return new WeakHashMap<>();}@Overrideprotected Map<TransmittableThreadLocal<?>, ?> childValue(Map<TransmittableThreadLocal<?>, ?> parentValue) {return new WeakHashMap<>(parentValue);}};
个人认为 holder 变量的设计,极大体现了作者的智慧,让人无数次献上膝盖。。。
// 调用 get() 方法时,同时将 this 指针放入 holder
public final T get() {T value = super.get();if (null != value) {addValue();}return value;
}
void addValue() {if (!holder.get().containsKey(this)) {holder.get().put(this, null); // WeakHashMap supports null value.}
}
// 调用 set() 方法时,同时处理 holder 中 this 指针
public final void set(T value) {super.set(value);if (null == value) { // may set null to remove valueremoveValue();} else {addValue();}
}
void removeValue() {holder.get().remove(this);
}
4、工作流程简介
自定义 TtlRunnable 实现 Runnable,TtlRunnable初始化方法中保持当前线程中已有的TransmittableThreadLocal
private TtlRunnable(Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {this.copiedRef = new AtomicReference<Map<TransmittableThreadLocal<?>, Object>>(TransmittableThreadLocal.copy());this.runnable = runnable;this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;
}
线程池中线程 调用run方法,执行前先backup holder中所有的TransmittableThreadLocal, copiedRef中不存在,holder存在的,说明是后来加进去的,remove掉holder中的;将copied中的TransmittableThreadLocal set到当前线程中
public void run() {Map<TransmittableThreadLocal<?>, Object> copied = copiedRef.get();if (copied == null || releaseTtlValueReferenceAfterRun && !copiedRef.compareAndSet(copied, null)) {throw new IllegalStateException("TTL value reference is released after run!");}Map<TransmittableThreadLocal<?>, Object> backup = TransmittableThreadLocal.backupAndSetToCopied(copied);try {runnable.run();} finally {TransmittableThreadLocal.restoreBackup(backup);}
}
执行后再恢复 backup 的数据到 holder 中(backup中不存在,holder中存在的TransmittableThreadLocal,从holder中remove掉),将 backup 中的 TransmittableThreadLocal set到当前线程中
5、参考文献
- transmittable-thread-local
TransmittableThreadLocal相关推荐
- 每日一博 - ThreadLocal VS InheritableThreadLocal VS TransmittableThreadLocal
文章目录 ThreadLocal 核心API ThreadLocal类 源码分析 set get remove 缺陷 InheritableThreadLocal 源码解析 局限性 Transmitt ...
- TransmittableThreadLocal 解决 线程池线程复用 无法复制 InheritableThreadLocal 的问题
ThreadLoacl,InheritableThreadLocal,原理,以及配合线程池使用的一些坑 TransmittableThreadLocal 原理 之前为了能让InheritableThr ...
- TransmittableThreadLocal 解决 线程池线程复用 无法复制 InheritableThreadLocal 的问题.
ThreadLoacl,InheritableThreadLocal,原理,以及配合线程池使用的一些坑 TransmittableThreadLocal 原理 之前为了能让InheritableThr ...
- TransmittableThreadLocal详解
1.简介 TransmittableThreadLocal 是Alibaba开源的.用于解决 "在使用线程池等会缓存线程的组件情况下传递ThreadLocal" 问题的 Inher ...
- 何为TransmittableThreadLocal
一.示例 线程池内的线程并没有父子关系,所以不适合InheritableThreadLocal的使用场景 public class ThreadPoolInheritableThreadLocalDe ...
- 通过transmittable-thread-local源码理解线程池线程本地变量传递的原理
前提 最近一两个月花了很大的功夫做UCloud服务和中间件迁移到阿里云的工作,没什么空闲时间撸文.想起很早之前写过ThreadLocal的源码分析相关文章,里面提到了ThreadLocal存在一个不能 ...
- TransmittableThreadLocal的简单使用 + 手写源码
文章目录 使用方法 原理 手写源码 之前有一篇文章谈到链路追踪场景下,需要在异步线程之间,实现跨线程的ThreadLocal传递, 简单场景可以用InheritableThreadLocal,但ITL ...
- ThreadLocal线程池使用和TransmittableThreadLocal值传递
一.ThreadLocal配合线程池 注意配合remove方法,线程池是对线程进行复用的,如果没有及时的清理,那么之前对该线程的使用,就会影响到后面的线程了,造成数据不准确. package com. ...
- 我居然被TransmittableThreadLocal框架作者评论了
大家好,我叫大鸡腿,大家可以关注下我,会持续更新技术文章还有人生感悟,感谢~ 前言 在掘金关注我的读者,可能不知道我之前是在csdn博客写了5年的博客专家,默默无闻的写了500多篇文章,当然有些是在前 ...
最新文章
- 转程序员,都去写一写前端代码吧
- MongoDB基础教程系列--目录结构
- ERROR 2059 (HY000): Authentication plugin ‘caching_sha2_password‘ cannot be loaded
- 贪心算法之——背包问题(nyoj106)
- 邮票的孔怎么做出来的_金银花茶是怎么做出来的呢
- 源码解析Spring Boot2默认数据库连接池HikariCP(高性能原因分析)
- 函数的基本知识,定义,调用,参数,返回值,说明文档,函数的嵌套及应用
- linux 下rpm软件的安装和卸载
- 一个Maven工程中,不同的模块需要不同的JDK进行编译的解决方案
- 【Windows】要不要升级Win11?Win11与Win10界面对比体验
- 西门子PLC学习记录
- 用 C 语言来刷 LeetCode,网友直呼:那是真的牛批...
- wr720n刷成网络打印_USB打印机通过路由共享wifi局域网打印,同网段
- Python 使用 PyOTP 实现二步验证
- 项目经历怎么写_工作经历、项目经验怎么写?
- Python爬取雪球7*24小时信息
- Eclipse3.5中安装maven插件出现“ the -vm option in eclipse.ini is pointing to a JDK”解决
- .Net6 图片转文字PictureToTxt
- 【数据结构】递归斐波那契数列的时间复杂度、空间复杂度
- vue 上传文件 和 下载文件
热门文章
- java中字符串的操作_java中字符串的操作
- python梯度下降法实现线性回归_梯度下降法的python代码实现(多元线性回归)
- sql的加减乘除运算_SQL简单查询语、运算符学习和练习
- 计算机科学入门指南游戏攻略,【基础攻略】从零开始新手入门指南
- STM32 ADC采样使用内部参考电压
- 手动修改Win7开机欢迎界面背景图片
- jsp页面实现打印 .
- mysql不存在就批量新增_mysql批量插入,存在则修改,不存在则插入
- ps自定义形状工具_【福利】3000款PS自定义形状免费打包下载
- docker pull的镜像放在哪里_Docker 安装ELK及Docker常见命令