同步操作将从 Gitee 极速下载/multi-thread-context 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
English Documentation | 中文文档
在使用线程池等会缓存线程的组件情况下,提供ThreadLocal
值的传递功能,解决异步执行时上下文传递的问题。
JDK
的InheritableThreadLocal
类可以完成父线程到子线程的值传递。但对于使用线程池等会缓存线程的组件的情况,线程由线程池创建好,并且线程是缓存起来反复使用的;这时父子线程关系的ThreadLocal
值传递已经没有意义,应用需要的实际上是把 任务提交给线程池时的ThreadLocal
值传递到 任务执行时。
本库提供的TransmittableThreadLocal
类继承并加强InheritableThreadLocal
类,解决上述的问题,使用详见User Guide。
整个库包含TTL
核心功能、线程池修饰及Agent
支持,只有不到 610 SLOC
代码行,非常精小。
欢迎
Issue
Fork
后提通过Pull Request
贡献代码
在ThreadLocal
的需求场景即是TTL
的潜在需求场景,如果你的业务需要『在使用线程池等会缓存线程的组件情况下传递ThreadLocal
』则是TTL
目标场景。
下面是几个典型场景例子。
SDK
传递信息各个场景的展开说明参见子文档 需求场景。
使用类TransmittableThreadLocal
来保存值,并跨线程池传递。
TransmittableThreadLocal
继承InheritableThreadLocal
,使用方式也类似。
相比InheritableThreadLocal
,添加了
protected
方法copy
ThreadLocal
值传递到 任务执行时时的拷贝行为,缺省传递的是引用。protected
方法beforeExecute
/afterExecute
Runnable
/Callable
)的前/后的生命周期回调,缺省是空操作。具体使用方式见下面的说明。
父线程给子线程传递值。
示例代码:
// 在父线程中设置
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
// =====================================================
// 在子线程中可以读取,值是"value-set-in-parent"
String value = parent.get();
这是其实是InheritableThreadLocal
的功能,应该使用InheritableThreadLocal
来完成。
但对于使用线程池等会缓存线程的组件的情况,线程由线程池创建好,并且线程是缓存起来反复使用的;这时父子线程关系的ThreadLocal
值传递已经没有意义,应用需要的实际上是把 任务提交给线程池时的ThreadLocal
值传递到 任务执行时。
解决方法参见下面的这几种用法。
Runnable
和Callable
使用com.alibaba.ttl.TtlRunnable
和com.alibaba.ttl.TtlCallable
来修饰传入线程池的Runnable
和Callable
。
示例代码:
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
Runnable task = new Task("1");
// 额外的处理,生成修饰了的对象ttlRunnable
Runnable ttlRunnable = TtlRunnable.get(task);
executorService.submit(ttlRunnable);
// =====================================================
// Task中可以读取,值是"value-set-in-parent"
String value = parent.get();
上面演示了Runnable
,Callable
的处理类似
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
Callable call = new Call("1");
// 额外的处理,生成修饰了的对象ttlCallable
Callable ttlCallable = TtlCallable.get(call);
executorService.submit(ttlCallable);
// =====================================================
// Call中可以读取,值是"value-set-in-parent"
String value = parent.get();
省去每次Runnable
和Callable
传入线程池时的修饰,这个逻辑可以在线程池中完成。
通过工具类com.alibaba.ttl.threadpool.TtlExecutors
完成,有下面的方法:
getTtlExecutor
:修饰接口Executor
getTtlExecutorService
:修饰接口ExecutorService
ScheduledExecutorService
:修饰接口ScheduledExecutorService
示例代码:
ExecutorService executorService = ...
// 额外的处理,生成修饰了的对象executorService
executorService = TtlExecutors.getTtlExecutorService(executorService);
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
Runnable task = new Task("1");
Callable call = new Call("2");
executorService.submit(task);
executorService.submit(call);
// =====================================================
// Task或是Call中可以读取,值是"value-set-in-parent"
String value = parent.get();
这种方式,实现线程池的传递是透明的,代码中没有修饰Runnable
或是线程池的代码。即可以做到应用代码 无侵入,后面文档有结合实际场景的架构对这一点的说明。
示例代码:
// 框架代码
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
// 应用代码
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable task = new Task("1");
Callable call = new Call("2");
executorService.submit(task);
executorService.submit(call);
// =====================================================
// Task或是Call中可以读取,值是"value-set-in-parent"
String value = parent.get();
Demo参见AgentDemo.java
。
目前Agent中,修饰了jdk
中的两个线程池实现类(实现代码在TtlTransformer.java
):
java.util.concurrent.ThreadPoolExecutor
java.util.concurrent.ScheduledThreadPoolExecutor
在Java
的启动参数加上:
-Xbootclasspath/a:/path/to/transmittable-thread-local-2.x.x.jar
-javaagent:/path/to/transmittable-thread-local-2.x.x.jar
注意:
TTL
的代码,所以TTL Agent
的Jar
要加到bootclasspath
上。Java命令行示例如下:
java -Xbootclasspath/a:transmittable-thread-local-2.0.0.jar \
-javaagent:transmittable-thread-local-2.0.0.jar \
-cp classes \
com.alibaba.ttl.threadpool.agent.demo.AgentDemo
有Demo演示『使用Java Agent来修饰线程池实现类』,执行工程下的脚本run-agent-demo.sh
即可运行Demo。
Java Agent
的使用方式在什么情况下TTL
会失效由于Runnable
和Callable
的修饰代码,是在线程池类中插入的。下面的情况会让插入的代码被绕过,传递会失效。
java.util.concurrent.ThreadPoolExecutor
和java.util.concurrent.ScheduledThreadPoolExecutor
,
覆盖了execute
、submit
、schedule
等提交任务的方法,并且没有调用父类的方法。execute
、submit
、schedule
等提交任务的方法禁止这些被覆盖,可以规避这个问题。java.util.Timer
类,使用Timer
时,TTL
会有问题。当前版本的Java API文档地址: http://alibaba.github.io/transmittable-thread-local/apidocs/
示例:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.1.0</version>
</dependency>
可以在 search.maven.org 查看可用的版本。
JavaLaunchHelper
的出错信息。1.7.0_40
有这个问题,1.6.0_51
、1.7.0_45
可以运行。1.7.0_45
还是有JavaLaunchHelper
的出错信息,但不影响运行。此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。