【多线程开发 2】从代码到实战TransmittableThreadLocal

【多线程开发 2】从代码到实战TransmittableThreadLocal

本文将从以下几个点讲解TransmittableThreadLocal(为了方便写以下简称ttl):

  • 前身

  • 是什么?

  • 可以用来做什么?

  • 源码原理

  • 实战

前身

ThreadLocal

要了解ttl就要先了解Java自带的类ThreadLocal,threadlocal是作为当前线程中属性ThreadLocalMap集合中的某一个Entry的key值Entry(threadlocl,value),虽然不同的线程之间threadlocal这个key值是一样,但是不同的线程所拥有的ThreadLocalMap是独一无二的,,用于存储一些线程不安全的公共变量,通过“给每一个线程一个线程不安全的变量的拷贝”,来达到线程安全的目的,就不会出现变量多个线程之间共享的问题。

ThreadLocal 变量通常被private static修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。

InheritableThreadLocal

使用ThreadLocal可以解决线程安全问题,但是也有一定的局限性,比如无法在父子线程之间传递信息,因此InheritableThreadLocal就是JDK为了解决这个问题而创建的

TTL是什么?可以做什么?

在现在开发的情况下肯定是需要复用线程的,如果说InheritableThreadLocal在生成子进程的时候会做信息传递,但是在使用线程池或者其他需要复用线程的地方,由于会不产生新的Thread,而是直接使用空闲的已建成的Thread,所以的话InheritableThreadLocal有时候会不能用,此时可以通过使用TTL解决对应问题。

img

读取线程间传递的ThreadLocal 值比较麻烦,ThreadLocal 和 InheritableThreadLocal 都没有开放内部的 ThreadLocalMap,不能直接读取。所以TTL继承了InheritableThreadLocal,在每次调用 ThreadLocal的 set/get/remove 等接口的时候,为 Thread 记录到底绑定了哪些需要发生线程间传递的 ThreadLocal 对象。

在创建runnable的时候,TTL会通过holder遍历全部的TTLRunnable快照,看出上下文中有哪些线程上的信息需要进行复制。

TTL的GitHub项目地址:https://github.com/alibaba/transmittable-thread-local,感兴趣的话可以查看一下源码,后续有时间的话我会出一篇详细解析TTL源码的项目地址。

实战

其中需要使用拦截器辅助实现,需要读者依据相应技术架构自行实现

使用TTL实现MDC日志在多系统之间的信息传输

public class CustomMdcAdapters implements MDCAdapter {private static final int WRITE_OPERATION = 1;private static final int MAP_COPY_OPERATION = 2;private static CustomMdcAdapters mtcMDCAdapter;static {mtcMDCAdapter = new CustomMdcAdapters();MDC.mdcAdapter = mtcMDCAdapter;}private final ThreadLocal<Map<String, String>> copyOnInheritThreadLocal = new TransmittableThreadLocal<>();private final ThreadLocal<Integer> lastOperation = new ThreadLocal<>();public static MDCAdapter getInstance() {return mtcMDCAdapter;}private static boolean wasLastOpReadOrNull(Integer lastOp) {return lastOp == null || lastOp == MAP_COPY_OPERATION;}private Integer getAndSetLastOperation(int op) {Integer lastOp = lastOperation.get();lastOperation.set(op);return lastOp;}private Map<String, String> duplicateAndInsertNewMap(Map<String, String> oldMap) {Map<String, String> newMap = Collections.synchronizedMap(new HashMap<>(16));if (oldMap != null) {// we don't want the parent thread modifying oldMap while we are// iterating over itsynchronized (oldMap) {newMap.putAll(oldMap);}}copyOnInheritThreadLocal.set(newMap);return newMap;}@Overridepublic void put(String key, String val) {if (key == null) {throw new IllegalArgumentException("key cannot be null");}Map<String, String> oldMap = copyOnInheritThreadLocal.get();Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);if (wasLastOpReadOrNull(lastOp) || oldMap == null) {Map<String, String> newMap = duplicateAndInsertNewMap(oldMap);newMap.put(key, val);} else {oldMap.put(key, val);}}@Overridepublic void remove(String key) {if (key == null) {return;}Map<String, String> oldMap = copyOnInheritThreadLocal.get();if (oldMap == null) {return;}Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);if (wasLastOpReadOrNull(lastOp)) {Map<String, String> newMap = duplicateAndInsertNewMap(oldMap);newMap.remove(key);} else {oldMap.remove(key);}}@Overridepublic void clear() {lastOperation.set(WRITE_OPERATION);copyOnInheritThreadLocal.remove();}@Overridepublic String get(String key) {final Map<String, String> map = copyOnInheritThreadLocal.get();if ((map != null) && (key != null)) {return map.get(key);} else {return null;}}public Map<String, String> getPropertyMap() {lastOperation.set(MAP_COPY_OPERATION);return copyOnInheritThreadLocal.get();}public Set<String> getKeys() {Map<String, String> map = getPropertyMap();if (map != null) {return map.keySet();} else {return null;}}@Overridepublic Map<String, String> getCopyOfContextMap() {Map<String, String> hashMap = copyOnInheritThreadLocal.get();if (hashMap == null) {return null;} else {return new HashMap<>(hashMap);}}@Overridepublic void setContextMap(Map<String, String> contextMap) {lastOperation.set(WRITE_OPERATION);Map<String, String> newMap = Collections.synchronizedMap(new HashMap<>(16));newMap.putAll(contextMap);copyOnInheritThreadLocal.set(newMap);}
}

使用TTL帮助实现web服务中的用户信息传输

public final class ContextsUtils {private ContextsUtils() {}private static final ThreadLocal<Map<String, String>> THREAD_LOCAL = new TransmittableThreadLocal<>();public static void putAll(Map<String, String> map) {map.forEach(ContextsUtils::set);}public static void set(String key, Object value) {Map<String, String> map = getLocalMap();map.put(key, value == null ? StrPool.EMPTY : value.toString());}public static <T> T get(String key, Class<T> type) {Map<String, String> map = getLocalMap();return Convert.convert(type, map.get(key));}public static <T> T get(String key, Class<T> type, Object def) {Map<String, String> map = getLocalMap();return Convert.convert(type, map.getOrDefault(key, String.valueOf(def == null ? StrPool.EMPTY : def)));}public static Map<String, String> getLocalMap() {Map<String, String> map = THREAD_LOCAL.get();if (map == null) {map = new ConcurrentHashMap<>(10);THREAD_LOCAL.set(map);}return map;}/*** 其他get/set各种信息需要读者依据业务自行实现。。。*/}

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

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

相关文章

C语言内存函数(与上篇字符函数及字符串函数一起食用效果更佳哦~)

顾名思义&#xff0c;内存函数就是针对内存块&#xff08;即一块内存&#xff09;来处理的。 因此本篇所讲的四种内存函数&#xff1a; memcpy&#xff08;内存拷贝&#xff09;memmove&#xff08;内存移动&#xff09;memset&#xff08;内存设置&#xff09;memcmp&#x…

5.Redis之常用数据结构单线程模型

围绕每个数据结构介绍相关命令当前版本的redis支持10个数据类型 Redis 底层在实现上述数据结构的时候,会在源码层面,针对上述实现进行特定的优化,来达到 节省时间/节省空间 效果,内部的具体实现的数据结构&#xff08;编码方式&#xff09;,还会有变数redis 承诺,现在我这有个 …

【Java EE】网络协议——HTTP协议

目录 1.HTTP 1.1HTTP是什么 1.2理解“应用层协议” 1.3理解HTTP协议的工作过程 2.HTTP协议格式 2.1抓包工具的使用 2.2抓包工具的原理 2.3抓包结果 3.协议格式总结 1.HTTP 1.1HTTP是什么 HTTP&#xff08;全称为“超文本传输协议”&#xff09;是一种应用非常广泛的应…

如何利用GitHubAction来发布自己的Python软件包

我们开发的python软件包如果想发布到网上&#xff0c;可以让其他人通过pip install下载&#xff0c;一般是把软件包发布到PYPI平台。 PYPI准备 我们要现在pypi注册登录一下 文件组织架构 一般的python软件包的文件组织架构为包名文件夹__init__.py程序&#xff0c;包文件夹的…

Django与前端框架协作开发实战:高效构建现代Web应用

title: Django与前端框架协作开发实战&#xff1a;高效构建现代Web应用 date: 2024/5/22 20:07:47 updated: 2024/5/22 20:07:47 categories: 后端开发 tags: DjangoREST前端框架SSR渲染SPA路由SEO优化组件库集成状态管理 第1章&#xff1a;简介 1.1 Django简介 Django是一…

论文阅读--ActionCLIP

原来的动作识别问题在于标注太难太贵&#xff0c;将动作表示为短语的latent space太大 本文的贡献&#xff1a;&#xff08;1&#xff09;将CLIP的image encoder换成video encoder&#xff0c;方法与CLIP4Clip几乎一样 &#xff08;2&#xff09;CLIP的ground truth来自于文本…

urllib_post请求_百度翻译之详细翻译

百度翻译有一个详细翻译的接口&#xff1a; post请求&#xff1a; 请求参数&#xff08;较多&#xff09;&#xff1a; 打印之后&#xff0c;发现有问题&#xff1a; 改一下请求头&#xff1a; 将Accept-Encoding注释掉&#xff0c;因为我们使用的是utf-8编码&#xff1a; 加上…

F28034中断

DSP中断 中断中断概述中断机制 中断 当CPU正在执行程序时&#xff0c;由于发生了某种随机的事件&#xff08;外部或内部&#xff09;&#xff0c;使CPU的执行中断&#xff0c;转而去执行某一段特殊的程序&#xff08;中断子程序或中断处理程序&#xff09;&#xff0c;以处理该…

轻型web服务器搭建 阿里云

1.购买云服务器 2.远程连接云服务器 重置实例密码 重置后要重启服务器 登录云服务器 密码就是刚刚重置的 3.安装宝塔面板 宝塔面板 - 简单好用的Linux/Windows服务器运维管理面板 (bt.cn) 回车则开始安装&#xff0c;过程中会多次让输入y表示确认下一步&#xff0c;过程大概2…

windows使用gzip和bzip2对文件进行压缩

git软件 git bash&#xff1a;下载地址https://git-scm.com/downloads&#xff0c;安装时一路next。 这个软件是给程序员提交代码用的工具&#xff0c;内置linux系统的命令行&#xff0c;可以使用linux系统特有的压缩软件gzip和bzip2. gzip使用 gzip一般用于压缩tar包&#…

基于机器学习的一线城市租房价格预测分析与实现,实现三种算法预测

本文旨在基于机器学习方法&#xff0c;对一线城市租房价格进行预测分析&#xff0c;并使用Matplotlib可视化、随机森林、一元线性回归和多元线性模型进行模型对比。通过爬取北京链家二手房数据作为研究对象&#xff0c;探讨了租房价格与各种因素之间的关系&#xff0c;阐述了研…

【YOLOv10训练教程】如何使用YOLOv10训练自己的数据集并且推理使用

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

【气象常用】间断时间序列图

效果图&#xff1a; 主要步骤&#xff1a; 1. 数据准备&#xff1a;随机数组 2. 图像绘制&#xff1a;绘制间断的时间序列 详细代码&#xff1a;着急的直接拖到最后有完整代码 步骤一&#xff1a;导入库包及图片存储路径并设置中文字体为宋体&#xff0c;西文为新罗马&…

冷干机使用中的注意事项

冷干机使用中的注意事项 使用冷干机时&#xff0c;以下是几个注意事项&#xff1a; 安装位置&#xff1a;选择一个通风良好、温度适宜的位置安装冷干机。确保周围环境没有过多的灰尘、腐蚀性气体或其他污染物&#xff0c;以免对冷干机的正常运行和寿命产生不利影响。 电源要求…

C++ STL 函数对象:隐藏的陷阱,如何避免状态带来的麻烦?

STL 函数对象&#xff1a;无状态即无压力 一、简介二、函数对象三、避免在函数对象中保存状态3.1、函数对象3.2、lambda 表达式 四、选择合适的更高层次的结构五、总结 一、简介 在使用 C 标准模板库 (STL) 时&#xff0c;函数对象 (Function Object) 是一种强大的工具&#x…

02324 自学考试 离散数学屈婉玲教材 目录

02324 自学考试 离散数学屈婉玲教材 目录 02324 自学考试 离散数学屈婉玲教材 02324离散数学全程班历年真题资料

技术面试,项目实战,求职利器

之前找工作一直想找一个能真正系统性学开发的地方&#xff0c;之前毕业找工作的时候无意间碰到下面这个网站&#xff0c;感觉还挺不错的&#xff0c;用上面的技术实战内容应对技术面试&#xff0c;也算是求职利器了。有需要的可以自取&#xff1a; https://how2j.cn?p156336 实…

VMware虚拟机中ubuntu使用记录(10)—— 如何在Ubuntu18.04中使用自己的单目摄像头运行ORB_SLAM3(亲测有效,踩坑记录)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、ORB_SLAM3源码编译二、ORB_SLAM3实时单目相机测试1. 查看摄像头的话题2. 运行测试 三. 运行测试可能的报错1. 报错一(1) 问题描述(2) 原因分析(3) 解决 2. …

SWM320系列应用

一、Swm320系列 SPI 应用 现象&#xff1a;应用SWM320的SPI1的模式0作为从机&#xff0c;整体产品硬件平台同步上电&#xff0c;从机的SPI无法正常工作&#xff0c;进不了中断&#xff0c;手工复位一次或连接SWD调试就正常了&#xff0c;这样的情况应该怎么解决&#xff1f;其…