ð 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<String>();
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> context = new TransmittableThreadLocal<String>();
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> context = new TransmittableThreadLocal<String>();
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<String>();
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<String>();
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 :-)


