ThreadLocal及阿里(TransmittableThreadLocal,TTL)分析

TTL类关系图
ThreadLocal <- InheritableThreadLocal <- TransmittableThreadLocal

在这里插入图片描述

1. ThreadLocal

ThreadLocal 类提供线程本地(局部)变量。每个线程都有自己独立初始化的变量副本。
TheadLocal 允许我们存储仅由特定线程访问的数据,从而起到线程隔离的作用,避免了并发场景下的线程安全问题。

1.1 使用场景

  • 线程持有自己的数据变量
/**
 * 每个线程拥有自己的Integer变量,默认初始化为0
 */
private static final ThreadLocal<Integer> INTEGER_THREAD_LOCAL = ThreadLocal.withInitial(() -> 0);
  • 避免数据竞争,每个线程持有自己的线程变量
/**
 * 每个线程拥有自己的SDF,避免竞争,保证线程安全
 */
private static final ThreadLocal<SimpleDateFormat> SDF_TL = ThreadLocal.withInitial(() -> {
    return new SimpleDateFormat("yyyyMMddHHmmss");
});
  • 数据传递,跨方法级别数据传递
/**
 * 数据传递上下文: LogbackMDCAdapter MDC 实际功能实现
 */
final ThreadLocal<Map<String, String>> context = new ThreadLocal<>();

1.2 ThreadLocal主要方法

// get() 获取线程本地变量,如果没有,则调用setInitialValue() 初始化并设置
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}
// 初始化
private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
    return value;
}
// 设置线程本地变量
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
// 移除线程本地变量
public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        m.remove(this);
}

1.3 实现原理

ThreadLocal实现主要依赖
1.ThreadLocal实例对象,作为线程访问数据的KEY存在。
2.ThreadLocalMap对象,每个线程有自己的map,ThreadLocal实例作为KEY。
注意:此处entry中的ThreadLocal key使用弱引用,防止内存泄漏,在清除方法中会清除所有 key为null的entry。

static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
}

ThreadLoclMap作为每个线程实例的字段存储在线程实例中:

public class Thread implements Runnable {
    /**
     * 与此线程相关的ThreadLocal值。此Map由 ThreadLocal 类维护。
     */
    ThreadLocal.ThreadLocalMap threadLocals = null;
    /**
     * 与此线程相关的 InheritableThreadLocal 值。此映射由 InheritableThreadLocal 类维护
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
}

1.4 缺陷

ThreadLocal在创建子线程时不会把线程本地变量拷贝到子线程中,这就会导致子线程无法获取到本地线程保存的线程信息

2. InheritableThreadLocal

InheritableThreadLocal 可继承的ThreadLocal,继承并扩扩展了原始ThreadLocal的功能,提供从父线程到子线程的value继承:创建子线程时,子线程接收父线程具有的 inheritable thread-local 值。

2.1 使用场景

  • 新建子线程需要集成父线程中的线程本地变量时,可以使用 InheritableThreadLocal 实现
/**
 * 可继承ThreadLocal,子线程将继承父线程中ITL变量value
 */
private static final ThreadLocal<Integer> BIZ_ITL = new InheritableThreadLocal();

/**
 * 运行结果:
 * main-thread-get:123
 * sub-thread-get:123
 */
public static void main(String[] args) {
    BIZ_ITL.set(123);
    System.out.println("main-thread-get:"+BIZ_ITL.get());
    new Thread(()->{
        System.out.println("sub-thread-get:"+BIZ_ITL.get());
    }).start();
}

2.2 InheritableThreadLocal 主要方法

  • getMap() createMap() 使用 ITLMap ,非 TLMap
ThreadLocalMap getMap(Thread t) {
   return t.inheritableThreadLocals;
}
void createMap(Thread t, T firstValue) {
    t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}

2.3 实现原理

main线程调用get方法跳转到InheritableThreadLocal重写的createMap,让inheritableThreadLocals赋初值;后续http请求会copy main线程中的数据,同样赋予inheritableThreadLocals 值。
子程继承父线程 线程本地变量值 是在Thread创建时,copy父类现成中的 ITLMap中的key和Value:
Thread构造函数:调用init方法,在init方法中子线程根据父线程的ITLMap创建自己的ITLMap(传递、继承)。

// 初始化Thread
public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
    // 获取父线程
    Thread parent = currentThread();
    // 省略其他步骤
    if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
}

2.4 缺陷

使用线程池时,线程不会每次都创建,也就不会进行父子线程之间的数据传递;如果使用池化的线程,就不会进行父子线程本地变量的拷贝。

3. TransmittableThreadLocal

3.1 使用场景

ThreadLocal和InheritableThreadLocal 能够完成变量的线程本地化和父子线程中的value传递。
但是现实项目中大多数线程池化在线程池中,因此,提交任务的线程无法将 提交现成的本地变量传递给执行task的任务线程。
TTL组件功能:在使用线程池等会池化复用线程的执行组件情况下,提供ThreadLocal值的传递功能,解决异步执行时上下文传递的问题。
业务期望:上下文生命周期的操作从业务逻辑中分离出来。业务逻辑不涉及生命周期,就不会有业务代码如疏忽清理而引发的问题了。

3.2 TransmittableThreadLocal主要方法

整个上下文的传递流程或说生命周期可以规范化成:
捕捉、回放和恢复这3个操作,即CRR(capture/replay/restore)模式。
CRR :

  1. capture方法:抓取线程(线程A)的所有TTL值。
  2. replay方法:在另一个线程(线程B)中,回放在capture方法中抓取的TTL值,并返回回放前TTL值的备份
  3. restore方法:恢复线程B执行replay方法之前的TTL值(即备份)
// 实现代码示例 TtlRunnable.class
// 初始化TtlRunnable对象
private TtlRunnable(@NonNull Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {
	// TransmittableThreadLocal.Transmitter.capture() 抓取当前线程中的TTL值的备份
    this.capturedRef = new AtomicReference<>(capture());
    this.runnable = runnable;
    this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;
}

@Override
public void run() {
	// 取出TTL值备份数据
    final Object captured = capturedRef.get();
    if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {
        throw new IllegalStateException("TTL value reference is released after run!");
    }
    // 回放在capture方法中抓取的TTL值并返回回放前TTL值的备份
    final Object backup = replay(captured);
    try {
        runnable.run();
    } finally {
        // 恢复线程B执行replay方法之前的TTL值(即备份)
        restore(backup);
    }
}

3.3 使用样例

private static final int DEFAULT_SIZE = 8;
private static final TransmittableThreadLocal<Map<String, Object>> CACHE = new TransmittableThreadLocal<Map<String, Object>>() {
    @Override
    protected Map<String, Object> initialValue() {
        return new HashMap<>(DEFAULT_SIZE);
    }
};

Executor ttlExecutor = TtlExecutors.getTtlExecutor(new ThreadPoolExecutor(
       properties.getCoreSize(),
        properties.getMaxSize(),
        properties.getKeepAliveSeconds(),
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(),
        new ThreadPoolExecutor.CallerRunsPolicy()
));

ttlExecutor.execute(TtlRunnable.get(() -> {})); 

参考资料
阿里TTL(TransmittableThreadLocal)分析

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#在既有数组中插入另一个数组:Array.Copy方法 vs 自定义插入方法

目录 一、使用的方法 1.使用Array.Copy方法 2.Copy(Array, Int32, Array, Int32, Int32) 3. 使用自定义的方法 二、实例 1.示例1&#xff1a;使用Array.Copy方法 2.示例2&#xff1a;使用自定义的方法 一、使用的方法 1.使用Array.Copy方法 首先定义了一个名为InsertAr…

可解释性AI(XAI):开启AI决策过程透明化,重塑信任与解决伦理偏见

文章目录 每日一句正能量前言可解释性AI的定义与重要性什么是可解释性&#xff1f;促进技术应用的可信度提高技术的透明度保护隐私和数据权益促进AI的社会接受度 可解释性AI的挑战与难点可解释性AI的应用场景后记 每日一句正能量 宁可因高目标而脖子硬&#xff0c;也不要为低目…

Java+SpringBoot:构建稳定高效的计算机基础教学平台

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

《Java程序设计》实验报告(四)之数据库操作

实验内容及步骤&#xff1a; 数据库的建立、删除等。&#xff08;1&#xff09;代码&#xff1a; package liyuxuan.study.java; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class CreateD…

npm 上传一个自己的应用(5) 删除自己发送到NPM官网的指定工具版本

上文 npm 上传一个自己的应用(4) 更新自己上传到NPM中的工具版本 并就行内容修改 我们更新了项目内容 然后更新了项目版本 那么 一些已经过时 甚至 当时上传的东西就有问题 我们又该怎么删除版本呢&#xff1f; 首先 我们还是要先登录 npm npm login然后 根据要求填写 Userna…

迅为RK3588开发板windows与开发板互传使用U盘进行拷贝

1 将 U 盘(U 盘的格式必须为 FAT32 格式&#xff0c;大小在 32G 以下)插到开发板的 usb 接口&#xff0c;串口打印信息如下所示&#xff0c;U 盘的设备节点是/dev/sdb4。U 盘的设备节点不是固定的&#xff0c;根据实际情况来查看设备节点。 2 输入以下命令挂载 U 盘&#xff0c…

新版本nginx安装提示需要openssl的问题

新版本的nginx安装的时候未发现openssl的路径&#xff0c;有两种方式解决 方式一&#xff1a; 找到本地nginx的解压目录中 &#xff0c;例如我的放到root下面了。 进入 /root/nginx1.24.0/auto/lib/openssl/conf 目录下修改内容 &#xff0c;这两行都需要修改&#xff0c;…

华为配置访客接入WLAN网络示例(MAC优先的Portal认证)

配置访客接入WLAN网络示例&#xff08;MAC优先的Portal认证&#xff09; 组网图形 图1 配置WLAN MAC优先的Portal认证示例组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件 业务需求 某企业为了提高WLAN网络的安全性&#xff0c;采用MAC优先的外置Portal认…

【51单片机】外部中断和定时器中断

目录 中断系统中断介绍中断概念 中断结构及相关寄存器中断结构中断相关寄存器 外部中断实验外部中断配置软件设计实验现象 定时器中断定时器介绍51 单片机定时器原理51 单片机定时/计数器结构51 单片机定时/计数器的工作方式 定时器配置硬件设计软件设计实验现象 中断系统 本章…

10个优化Instagram SEO的必学策略

Instagram SEO 是优化 Instagram 内容以使其在平台搜索结果中被发现的做法。如果你希望你可以更快的让你的Ins获得流量&#xff0c;做好SEO就成功了一半。Instagram 搜索结果包括相关内容、帐户、音频、主题标签和地点&#xff0c;下面为你总结10个策略技巧&#xff01; 一、In…

三网码支付系统源码,三网免挂有PC软件,有云端源码,附带系统搭建教程

搭建教程 1.先上传云端源码 然后配置Core/Config.php文件里面数据库信息注改&#xff1b;数据库帐号密码 2.云端源码里面Core/Api_Class/Instant_Url_List.php文件配置终端地址注改&#xff1b;第4 http://终端地址/ 3.导入云端数据库 账号admin 密码123456注改&#xff1…

使用python揭秘CSDN热门付费专栏惊人真相

文章目录 1.csdn付费专栏词云2.浏览器抓包分析3.API接口测试4.需要使用的python库5.爬虫与数据分析设计6. 完整代码7.最终的成果8.惊人真相在这里 1.csdn付费专栏词云 我们如何分析csdn热门付费专栏呢&#xff1f; 热门专栏是动态的&#xff0c;所以我们爬取的数据是一直变化的…

5-4、S加减单片机程序【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍实现步进电机S曲线运动的代码 一、目标功能 实现步进电机转动总角度720&#xff0c;其中加减速各90 加速段&#xff1a;加速类型&#xff1a;S曲线  加速角度&#xff1a;角度为90  起步速度…

【OpenVINO™】在 MacOS 上使用 OpenVINO™ C# API 部署 Yolov5 (下篇)

在 MacOS 上使用 OpenVINO™ C# API 部署 Yolov5 &#xff08;下篇&#xff09; 项目介绍 YOLOv5 是革命性的 "单阶段"对象检测模型的第五次迭代&#xff0c;旨在实时提供高速、高精度的结果&#xff0c;是世界上最受欢迎的视觉人工智能模型&#xff0c;代表了Ult…

使用ChatGpt和文心一言辅助文章创作

近期在写数字水浒系列文章&#xff0c;使用了ChatGpt和文心一言进行辅助创作&#xff0c;整体感受不错&#xff0c;提高了工作效率。 在使用过程中&#xff0c;感觉文心的中文能力更强一些&#xff0c;主要体现在&#xff1a; 1 语料库更大&#xff0c;比如对水浒传了解的更多…

Blender_查看版本

Blender_查看版本 烦人的烦恼&#xff0c;没找见哪儿可以查看版本&#xff1f; 算是个隐蔽的角落&#xff01;

MoE-LLaVA:具有高效缩放和多模态专业知识的大型视觉语言模型

视觉和语言模型的交叉导致了人工智能的变革性进步&#xff0c;使应用程序能够以类似于人类感知的方式理解和解释世界。大型视觉语言模型(LVLMs)在图像识别、视觉问题回答和多模态交互方面提供了无与伦比的能力。 MoE-LLaVA利用了“专家混合”策略融合视觉和语言数据&#xff0…

如何利用大模型结合文本语义实现文本相似度分析?

常规的文本相似度计算有TF-IDF&#xff0c;Simhash、编辑距离等方式&#xff0c;但是常规的文本相似度计算方式仅仅能对文本表面相似度进行分析计算&#xff0c;并不能结合语义分析&#xff0c;而如果使用机器学习、深度学习的方式费时费力&#xff0c;效果也不一定能达到我们满…

Linux联网安装MySQL Server

yum安装 以下代码复制粘贴到控制台即可 yum list | grep mysql-server #查看可以下载的MySQLyum install -y mysql-server #安装MySQLmysql_secure_installation #引导安装 引导安装实例如下 systemctl enable mysqld 设置开机自动启动 systemctl sta…

transformer剪枝论文汇总

文章目录 NN Pruning摘要实验 大模型剪枝LLM-PrunerSparseGPT LTPVTPWidth & Depth PruningPatch SlimmingDynamicViTSPViTDynamicBERTViT SlimmingFastFormersNViTUVCPost-training pruning NN Pruning 《Block Pruning For Faster Transformers》 《为更快的transformer…