📌 TransmittableThreadLocal(TTL) 📌
🔧 功能🎨 需求场景👥 User Guide🔌 Java API Docs�?� Maven�?赖🔨 关于编译构建与IDE开�?��?� FAQ🗿 更多文档📚 相关资料👷 Contributors
🔧 功能
ThreadLocalå€¼çš„ä¼ é€’åŠŸèƒ½ï¼Œè§£å†³å¼‚æ¥æ‰§è¡Œæ—¶ä¸Šä¸‹æ–‡ä¼ 递的问题。
一个Javaæ ‡å‡†åº“æœ¬åº”ä¸ºæ¡†æž¶/ä¸é—´ä»¶è®¾æ–½å¼€ï¿½?��??ä¾›çš„æ ‡ï¿½?能力,本库功能�?�焦 & 0�?赖,支�?Java 16/15/14/13/12/11/10/9/8/7/6。
JDKçš„InheritableThreadLocal类�?�以完�?父线程到�?çº¿ç¨‹çš„å€¼ä¼ é€’ã€‚ä½†å¯¹äºŽä½¿ç”¨çº¿ç¨‹æ± ç‰ä¼šæ± 化�?ç”¨çº¿ç¨‹çš„æ‰§è¡Œç»„ä»¶çš„æƒ…å†µï¼Œçº¿ç¨‹ç”±çº¿ç¨‹æ± åˆ›å»ºå¥½ï¼Œå¹¶ä¸”çº¿ç¨‹æ˜¯æ± åŒ–èµ·ï¿½?��??�?使用的;这时父�?线程关系的ThreadLocalå€¼ä¼ é€’å·²ï¿½?没有�?义,应用需�?的实际上是把 任务�??äº¤ç»™çº¿ç¨‹æ± æ—¶çš„ThreadLocalå€¼ä¼ é€’åˆ° 任务执行时。
本库�??供的TransmittableThreadLocalç±»ç»§æ‰¿å¹¶åŠ å¼ºInheritableThreadLocal类,解决上述的问题,使用详�?User Guide。
整个TransmittableThreadLocalåº“çš„æ ¸å¿ƒåŠŸèƒ½ï¼ˆç”¨æˆ·API与框架/ä¸é—´ä»¶çš„集�?API�?çº¿ç¨‹æ± ExecutorService/ForkJoinPool/TimerTask�?�其线程工厂的Wrapper),�?�有 ~1000 SLOC代�?行,�?�常精�?。
欢迎
- 建议和�??问,�??交
Issue - 贡献和改进,
Fork�?��??通过Pull Request贡献代�?
🎨 需求场景
在ThreadLocal的需求场景�?�是TransmittableThreadLocalçš„æ½œåœ¨éœ€æ±‚åœºæ™¯ï¼Œå¦‚æžœä½ çš„ä¸šåŠ¡éœ€ï¿½?ã€Žåœ¨ä½¿ç”¨çº¿ç¨‹æ± ç‰ä¼šæ± 化�?ç”¨çº¿ç¨‹çš„æ‰§è¡Œç»„ä»¶æƒ…å†µä¸‹ä¼ é€’ThreadLocal�?则是TransmittableThreadLocalç›®æ ‡åœºæ™¯ã€‚
下�?ï¿½æ˜¯å‡ ä¸ªå…¸åž‹åœºæ™¯ä¾‹ï¿½?。
- 分布�?跟踪系统 或 全链路压测(�?ï¿½é“¾è·¯æ‰“æ ‡ï¼‰
- 日志收集记录系统上下文
Session级Cache- 应用容器或上层框架跨应用代�?给下层
SDKä¼ é€’ä¿¡ï¿½?�
�?�个场景的展开说明�?��?�?文档 需求场景。
👥 User Guide
使用类TransmittableThreadLocal�?��?å˜å€¼ï¼Œå¹¶è·¨çº¿ç¨‹æ± ä¼ é€’ã€‚
TransmittableThreadLocal继承InheritableThreadLocal,使用方�?也类似。
相比InheritableThreadLocalï¼Œæ·»åŠ äº†
copy方法
用于定制 任务�??äº¤ç»™çº¿ç¨‹æ± æ—¶ çš„ThreadLocalå€¼ä¼ é€’åˆ° 任务执行时 的拷�?行为,缺�?ä¼ é€’çš„æ˜¯å¼•ç”¨ã€‚
注�?ï¼šå¦‚æžœè·¨çº¿ç¨‹ä¼ é€’äº†å¯¹è±¡å¼•ç”¨å› ä¸ºï¿½?�?有线程�?é—,与InheritableThreadLocal.childValueä¸€æ ·ï¼Œä½¿ç”¨è€…/业务逻辑�?注�?ä¼ é€’å¯¹è±¡çš„çº¿ç¨‹å®‰å…¨ã€‚protectedçš„beforeExecute/afterExecute方法
执行任务(Runnable/Callable)的�?/�?�的生命周期回调,缺�?是空�?作。
具体使用方�?�?下�?�的说明。
1. 简�?�使用
父线程给�?çº¿ç¨‹ä¼ é€’å€¼ã€‚
示例代�?:
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程ä¸è®¾ç½®
context.set("value-set-in-parent");
// =====================================================
// 在�?线程ä¸ï¿½?�以读�?�,值是"value-set-in-parent"
String value = context.get();# 完整�?��?行的Demo代�?�?��?SimpleDemo.kt。
这是其实是InheritableThreadLocal的功能,应该使用InheritableThreadLocal�?�完�?。
ä½†å¯¹äºŽä½¿ç”¨çº¿ç¨‹æ± ç‰ä¼šæ± 化�?ç”¨çº¿ç¨‹çš„æ‰§è¡Œç»„ä»¶çš„æƒ…å†µï¼Œçº¿ç¨‹ç”±çº¿ç¨‹æ± åˆ›å»ºå¥½ï¼Œå¹¶ä¸”çº¿ç¨‹æ˜¯æ± åŒ–èµ·ï¿½?��??�?使用的;这时父�?线程关系的ThreadLocalå€¼ä¼ é€’å·²ï¿½?没有�?义,应用需�?的实际上是把 任务�??äº¤ç»™çº¿ç¨‹æ± æ—¶çš„ThreadLocalå€¼ä¼ é€’åˆ° 任务执行时。
解决方法�?��?下�?ï¿½çš„è¿™å‡ ï¿½?用法。
2. �?�?çº¿ç¨‹æ± ä¸ä¼ 递值
2.1 修饰Runnable和Callable
使用TtlRunnableå’ŒTtlCallable�?ï¿½ä¿®é¥°ä¼ å…¥çº¿ç¨‹æ± çš„Runnableå’ŒCallable。
示例代�?:
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程ä¸è®¾ç½®
context.set("value-set-in-parent");
Runnable task = new RunnableTask();
// �?外的处�?�,生�?修饰了的对象ttlRunnable
Runnable ttlRunnable = TtlRunnable.get(task);
executorService.submit(ttlRunnable);
// =====================================================
// Taskä¸ï¿½?�以读�?�,值是"value-set-in-parent"
String value = context.get();上�?�演示了Runnable,Callable的处�?�类似
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程ä¸è®¾ç½®
context.set("value-set-in-parent");
Callable call = new CallableTask();
// �?外的处�?�,生�?修饰了的对象ttlCallable
Callable ttlCallable = TtlCallable.get(call);
executorService.submit(ttlCallable);
// =====================================================
// Callä¸ï¿½?�以读�?�,值是"value-set-in-parent"
String value = context.get();# 完整�?��?行的Demo代�?�?��?TtlWrapperDemo.kt。
整个过程的完整时�?图
2.2 修饰线程æ±
�?去�?次Runnableå’ŒCallableä¼ å…¥çº¿ç¨‹æ± æ—¶çš„ä¿®é¥°ï¼Œè¿™ä¸ªé€»è¾‘ï¿½?ï¿½ä»¥åœ¨çº¿ç¨‹æ± ä¸å®Œï¿½?。
通过工具类com.alibaba.ttl.threadpool.TtlExecutors完�?,有下�?�的方法:
getTtlExecutor:修饰接�?�ExecutorgetTtlExecutorService:修饰接�?�ExecutorServicegetTtlScheduledExecutorService:修饰接�?�ScheduledExecutorService
示例代�?:
ExecutorService executorService = ...
// �?外的处�?�,生�?修饰了的对象executorService
executorService = TtlExecutors.getTtlExecutorService(executorService);
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程ä¸è®¾ç½®
context.set("value-set-in-parent");
Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);
// =====================================================
// Task或是Callä¸ï¿½?�以读�?�,值是"value-set-in-parent"
String value = context.get();# 完整�?��?行的Demo代�?�?��?TtlExecutorWrapperDemo.kt。
2.3 使用Java Agent�?�修饰JDKçº¿ç¨‹æ± å®žçŽ°ç±»
这�?方�?ï¼Œå®žçŽ°çº¿ç¨‹æ± çš„ä¼ é€’æ˜¯ï¿½?明的,业务代�?䏿²¡æœ‰ä¿®é¥°Runnableæˆ–æ˜¯çº¿ç¨‹æ± çš„ä»£ï¿½?。�?��?�以�?�到应用代�? æ— ä¾µå…¥ã€‚
# 关于 æ— ä¾µå…¥ 的更多说明�?��?文档Java Agent方�?对应用代�?æ— ä¾µå…¥ã€‚
示例代�?:
// ## 1. 框架上层逻辑,�?�ç»ï¿½?程框架调用业务 ##
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
context.set("value-set-in-parent");
// ## 2. 应用逻辑,�?�ç»ï¿½?程业务调用框架下层逻辑 ##
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);
// ## 3. 框架下层逻辑 ##
// Task或是Callä¸ï¿½?�以读�?�,值是"value-set-in-parent"
String value = context.get();Demo�?��?AgentDemo.kt。执行工程下的脚本scripts/run-agent-demo.sh�?��?��?行Demo。
目�?TTL Agentä¸ï¼Œä¿®é¥°äº†çš„JDK执行器组件(�?ï¿½å¦‚çº¿ç¨‹æ± ï¼‰å¦‚ä¸‹ï¼š
java.util.concurrent.ThreadPoolExecutor和java.util.concurrent.ScheduledThreadPoolExecutor- 修饰实现代�?在
TtlExecutorTransformlet.java。
- 修饰实现代�?在
java.util.concurrent.ForkJoinTask(对应的执行器组件是java.util.concurrent.ForkJoinPool)- 修饰实现代�?在
TtlForkJoinTransformlet.java。从版本2.5.1开始支�?。 - 注�?:
Java 8引入的CompletableFuture与(并行执行的)Stream底层是通过ForkJoinPool�?�执行,所以支�?ForkJoinPool�?�,TTL也就�?明支�?了CompletableFuture与Stream。🎉
- 修饰实现代�?在
java.util.TimerTask的�?类(对应的执行器组件是java.util.Timer)- 修饰实现代�?在
TtlTimerTaskTransformlet.java。从版本2.7.0开始支�?。 - 注�?:从
2.11.2版本开始缺�?开�?�TimerTaskçš„ä¿®é¥°ï¼ˆå› ä¸ºï¿½?�?æ£ç¡®æ€§æ˜¯ç¬¬ä¸€ï¿½?,而�?是最佳实践『�?推�??使用TimerTask�?:);2.11.1版本�?�其之�?的版本没有缺�?开�?�TimerTask的修饰。 - 使用
Agent�?�数ttl.agent.enable.timer.task开�?�/å…³é—TimerTask的修饰:-javaagent:path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.enable.timer.task:true-javaagent:path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.enable.timer.task:false
- 更多关于
TTL Agent�?�数的�?置说明详�?TtlAgent.java的JavaDoc。
- 修饰实现代�?在
关于
java.util.TimerTask/java.util.Timer
Timer是JDK 1.3的�?类,�?推�??使用Timer类。推�??用
ScheduledExecutorService。
ScheduledThreadPoolExecutor实现更强壮,并且功能更丰富。 如支�?�?ç½®çº¿ç¨‹æ± çš„å¤§ï¿½?(Timer�?�有一个线程);Timer在Runnableä¸æŠ›å‡ºå¼‚å¸¸ä¼šä¸æ¢å®šæ—¶æ‰§è¡Œã€‚更多说明�?��?10. Mandatory Run multiple TimeTask by using ScheduledExecutorService rather than Timer because Timer will kill all running threads in case of failing to catch exceptions. - Alibaba Java Coding Guidelines。
关于boot class path设置
å› ä¸ºä¿®é¥°äº†JDKæ ‡å‡†åº“çš„ç±»ï¼Œæ ‡å‡†åº“ç”±bootstrap class loaderåŠ è½½ï¼›ä¿®é¥°ï¿½?�的JDK类引用了TTL的代�?,所以Java Agent使用方�?下TTL Jar文件需�?�?置到boot class path上。
TTL从v2.6.0å¼€å§‹ï¼ŒåŠ è½½TTL Agent时会自动设置TTL Jar到boot class path上。
注�?:�?能修改从Maven库下载的TTL Jar文件�??(形如transmittable-thread-local-2.x.x.jar)。
如果修改了,则需�?自己手动通过-Xbootclasspath JVM�?�数�?�显�?�?置(就�?TTL之�?的版本的�?ï¿½æ³•ä¸€æ ·ï¼‰ã€‚
自动设置TTL Jar到boot class path的实现是通过指定TTL Java Agent Jar文件里manifest文件(META-INF/MANIFEST.MF)的Boot-Class-Path属性:
Boot-Class-PathA list of paths to be searched by the bootstrap class loader. Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms). These paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed. Paths are searched in the order listed.
更多详�?
Java Agent规范 -JavaDoc- JAR File Specification - JAR Manifest
- Working with Manifest Files - The Javaâ„¢ TutorialsHide
Java的�?�动�?�数�?置
在Java的�?�动�?ï¿½æ•°åŠ ä¸Šï¼š-javaagent:path/to/transmittable-thread-local-2.x.x.jar。
如果修改了下载的TTL的Jar的文件�??(transmittable-thread-local-2.x.x.jar),则需�?自己手动通过-Xbootclasspath JVM�?�数�?�显�?�?置:
比如修改文件�??�?ttl-foo-name-changed.jarï¼Œåˆ™è¿˜åŠ ä¸ŠJava的�?�动�?�数:-Xbootclasspath/a:path/to/ttl-foo-name-changed.jar
Java命令行示例如下:
java -javaagent:path/to/transmittable-thread-local-2.x.x.jar \
-cp classes \
com.alibaba.demo.ttl.agent.AgentDemo或是
# 如果修改了TTL jar文件�?? 或 TTL版本是 2.6.0 之�?,
# 则还需�?显�?设置 -Xbootclasspath �?�数
java -javaagent:path/to/ttl-foo-name-changed.jar \
-Xbootclasspath/a:path/to/ttl-foo-name-changed.jar \
-cp classes \
com.alibaba.demo.ttl.agent.AgentDemo🔌 Java API Docs
当�?版本的Java API文档地�?�: https://alibaba.github.io/transmittable-thread-local/apidocs/
�?� Maven�?赖
示例:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.11.5</version>
</dependency>�?�以在 search.maven.org 查看�?�用的版本。
🔨 关于编译构建与IDE开�?�
编译构建的环境�?求: JDK 8~11;用Maven常规的方�?执行编译构建�?��?�:
# 在工程ä¸å·²ï¿½?包�?�了符�?�版本�?求的Maven,直接�?行 å·¥ç¨‹æ ¹ç›®å½•ä¸‹çš„mvnw;并�?需�?先手动自己安装好Maven。
# �?行测试Case
./mvnw test
# 编译打包
./mvnw package
# �?行测试Case�?编译打包�?安装TTL库到Maven本地
./mvnw install
#####################################################
# å¦‚æžœä½¿ç”¨ä½ è‡ªå·±å®‰è£…çš„`Maven`,版本�?求:maven 3.3.9+
mvn install如何用IDE�?�开�?�时注�?点,更多说明�?��? 文档 如何用IDE开�?� - Developer Guide。
�?� FAQ
- Mac OS X下,使用javaagent,�?�能会报
JavaLaunchHelper的出错信�?�。
JDK Bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8021205
�?�以�?�一个版本的JDK。我的开�?�机上1.7.0_40有这个问题,1.6.0_51�?1.7.0_45�?�以�?行。
#1.7.0_45还是有JavaLaunchHelper的出错信�?�,但�?影�?�?行。
🗿 更多文档
📚 相关资料
Jdk Core Classes
👷 Contributors
- Jerry Lee <oldratlee at gmail dot com> @oldratlee
- Yang Fang <snoop.fy at gmail dot com> @driventokill
- Zava Xu <zava.kid at gmail dot com> @zavakid
- wuwen <wuwen.55 at aliyun dot com> @wuwen5
- Xiaowei Shi <179969622 at qq dot com> @xwshiustc
- David Dai <351450944 at qq dot com> @LNAmp
- Your name here :-)


