ThreadLocal (三):为何TransmittableThreadLocal
一、示例
线程池内的线程并没有父子关系,所以不适合InheritableThreadLocal的使用场景
public class ThreadPoolInheritableThreadLocalDemo {
// static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
// static ExecutorService pool = Executors.newFixedThreadPool(2);
static TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
static ExecutorService pool = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(3));
public static void main(String[] args) {
for(int i=0;i<100;i++) {
int j = i;
pool.execute(new Thread(new Runnable() {
@Override
public void run() {
ThreadPoolInheritableThreadLocalDemo.threadLocal.set("superWorld"+j);
ThreadPoolInheritableThreadLocalDemo.pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" : " +
ThreadPoolInheritableThreadLocalDemo.threadLocal.get());
}
});
}
}));
}
}
}
二、TransmittableThreadLocal实现分析

读取线程间传递的ThreadLocal 值比较麻烦,ThreadLocal 和 InheritableThreadLocal 都没有开放内部的 ThreadLocalMap,不能直接读取。
所以要么自己完全实现一套 ThreadLocalMap 机制(如 Netty 的 FastThreadLocal),要么就是自己实现 ThreadLocal 的子类,在每次调用 ThreadLocal
的 set/get/remove 等接口的时候,为 Thread 记录到底绑定了哪些需要发生线程间传递的 ThreadLocal 对象。
/**
*实际存储值的工作还是父类ThreadLocal完成
*TransmittableThreadLocal 只是记录了哪些线程使用了TransmittableThreadLocal对象
*/
@Override
public final void set(T value) {
super.set(value);
if (null == value) { // may set null to remove value
removeValue();
} else {
addValue();
}
}/**
*holder 只是为了记录使用了哪些 TransmittableThreadLocal 对象
*在构造TtlRunnable/TtlCallable 的时候, 通过holder取得对应的TransmittableThreadLocal
*InheritableThreadLocal的默认值是WeakHashMap
*/
private static InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>> holder =
new InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>>() {
@Override
protected Map<TransmittableThreadLocal<?>, ?> initialValue() {
return new WeakHashMap<TransmittableThreadLocal<?>, Object>();
} @Override
protected Map<TransmittableThreadLocal<?>, ?> childValue(Map<TransmittableThreadLocal<?>, ?> parentValue) {
return new WeakHashMap<TransmittableThreadLocal<?>, Object>(parentValue);
}
}; private void addValue() {
if (!holder.get().containsKey(this)) {
holder.get().put(this, null); // WeakHashMap supports null value.
}
} private void removeValue() {
holder.get().remove(this);
}
调用ThreadPoolInheritableThreadLocalDemo.threadLocal.set("superWorld"+j)时,
holder.get().containskey(this) 为false

2. TtlRunnable
构造TtlRunable时,设置线程对应的Map<TransmittableThreadLocal<?>, Object>>
private TtlRunnable(Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {
//
this.copiedRef = new AtomicReference<Map<TransmittableThreadLocal<?>, Object>>(TransmittableThreadLocal.copy());
this.runnable = runnable;
this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;
}
TransmittableThreadLocal.copy
static Map<TransmittableThreadLocal<?>, Object> copy() {
Map<TransmittableThreadLocal<?>, Object> copy = new HashMap<TransmittableThreadLocal<?>, Object>();
for (TransmittableThreadLocal<?> threadLocal : holder.get().keySet()) {
copy.put(threadLocal, threadLocal.copyValue());
}
return copy;
}

3.运行时,备份和恢复Map<TransmittableThreadLocal<?>, Object>
TtlRunnable#run
@Override
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);
}
}

参考:
ThreadLocal (三):为何TransmittableThreadLocal的更多相关文章
- ThreadLocal系列(三)-TransmittableThreadLocal的使用及原理解析
ThreadLocal系列(三)-TransmittableThreadLocal的使用及原理解析 上一篇:ThreadLocal系列(二)-InheritableThreadLocal的使用及原理解 ...
- ThreadLocal的进化——TransmittableThreadLocal
上一篇文章中,我们谈到了 InheritableThreadLocal,它解决了 ThreadLocal 针对父子线程无法共享上下文的问题.但我们可能听说过阿里的开源产品TransmittableTh ...
- ThreadLocal系列(二)-InheritableThreadLocal的使用及原理解析
ThreadLocal系列之InheritableThreadLocal的使用及原理解析(源码基于java8) 上一篇:ThreadLocal系列(一)-ThreadLocal的使用及原理解析 下一篇 ...
- ThreadLocal的几种误区
最近由于需要用到ThreadLocal,在网上搜索了一些相关资料,发现对ThreadLocal经常会有下面几种误解 一.ThreadLocal是java线程的一个实现 ThreadLoca ...
- 【原理】Java的ThreadLocal实现原理浅读
当前线程的值传递,ThreadLocal 通过ThreadLocal设值,在线程内可获取,即时获取值时在其它Class或其它Method. public class BasicUsage { priv ...
- ThreadLocal的使用场景分析
目录 一.ThreadLocal介绍 二.使用场景1——数据库事务问题 2.1 问题背景 2.2 方案1-修改接口传参 2.3 方案2-使用ThreadLocal 三.使用场景2——日志追踪问题 四. ...
- 多线程程序设计学习(12)Thread-soecific storage pattern
Thread-Specific-Storage[线程保管箱] 一:Thread-Specific Storage的参与者--->记录日志的线程(ClientThread)--->负责获取不 ...
- 多线程学习三:Thread API,ThreadLocal,synchronized,volatile和Condition
一.Thread API: setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) 首先要了解什么是Thread. ...
- 使用 transmittable-thread-local 组件解决 ThreadLocal 父子线程数据传递问题
在某个项目中,需要使用mybatis-plus多租户功能以便数据隔离,前端将租户id传到后端,后端通过拦截器将该租户id设置到ThreadLocal以便后续使用,代码大体上如下所示: ThreadLo ...
随机推荐
- Atitit. atiJavaExConverter4js 新的特性
Atitit. atiJavaExConverter4js 新的特性 1.1. V1新特性1 1.2. V2 新特性1 2. Keyword1 3. Catch1 4. Convert n Thro ...
- Atitit,通过pid获取进程文件路径 java php c#.net版本大总结
Atitit,通过pid获取进程文件路径 java php c#.net版本大总结 1. 通过PID获取进程路径的几种方法2 1.1. GetModuleFileNameEx 想获得进程可执行文件的 ...
- html之全局属性
html全局属性有很多,下面说说常用的几个: 1.class 这个就不用多说了!规定类名. 2.contenteditable 规定元素是否可以编辑 语法: <element contented ...
- 使用httpClient发送get\post请求
maven依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId&g ...
- Kafka具体解释五、Kafka Consumer的底层API- SimpleConsumer
1.Kafka提供了两套API给Consumer The high-level Consumer API The SimpleConsumer API 第一种高度抽象的Consumer API,它使用 ...
- archive的时候报“ no identity found"错误 解决方式
第一步: 在xcode----target----general----identity----team里 增加你们公司的账号就能够了 第二步: Xcode > Preferences > ...
- CDH配置JAVA_HOME
jdk成功安装 java -version 正确显示版本 echo $JAVA_HOME 正确输出路径 但CDH链接数据库还是报错: Error: JAVA_HOME is not set and ...
- OpenCV中Camshitf算法学习(补充)
结合OpenCV中Camshitf算法学习,做一些简单的补充,包括: 实现全自动跟随的一种方法 参考opencv中的相关demo,可以截取目标物体的图片,由此预先计算出其色彩投影图,用于实际的目标跟随 ...
- JavaScript 对大小写敏感。
JavaScript 对大小写是敏感的. 当编写 JavaScript 语句时,请留意是否关闭大小写切换键. 函数 getElementById 与 getElementbyID 是不同的. 同样,变 ...
- Python Theano TypeError: Cannot convert Type TensorType(float64, vector) (of Variable Subtensor{int64:int64:}.0) into Type TensorType(float64, matrix)
参考: https://groups.google.com/forum/#!topic/theano-users/teA-07wOFpE 这个问题出现的原因是,我在读文件的时候,应该Train_X读成 ...