[心缘地方]同学录
首页 | 功能说明 | 站长通知 | 最近更新 | 编码查看转换 | 代码下载 | 常见问题及讨论 | 《深入解析ASP核心技术》 | 王小鸭自动发工资条VBA版
登录系统:用户名: 密码: 如果要讨论问题,请先注册。

[备忘]线程Local值在线程池中的传递,使用transmittable-thread-local

上一篇:[备忘]多个请求卡在java.net.InetAddress.getAddressesFromNameService
下一篇:没有了

添加日期:2025/3/31 18:08:58 快速返回   返回列表 阅读12次
https://github.com/alibaba/transmittable-thread-local
解决线程Local值,在线程池里没有传递的问题。

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>transmittable-thread-local</artifactId>
   <version>2.12.1</version>
</dependency>

使用类TransmittableThreadLocal来保存值,并跨线程池传递。
TransmittableThreadLocal继承InheritableThreadLocal,使用方式也类似

简单使用:
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();

// =====================================================
// 在父线程中设置
context.set("value-set-in-parent");
// =====================================================

// 在子线程中可以读取,值是"value-set-in-parent"
String value = context.get();
// =====================================================


线程池需要装饰一下,两种办法,二选一即可。
(1)使用TtlRunnable和TtlCallable来修饰传入线程池的Runnable和Callable。
Runnable task = new RunnableTask();
// 额外的处理,生成修饰了的对象ttlRunnable
Runnable ttlRunnable = TtlRunnable.get(task);
executorService.submit(ttlRunnable);

(2)修饰线程池,省去每次Runnable和Callable传入线程池时的修饰,这个逻辑可以在线程池中完成。

通过工具类TtlExecutors完成,有下面的方法:
getTtlExecutor:修饰接口Executor
getTtlExecutorService:修饰接口ExecutorService
getTtlScheduledExecutorService:修饰接口ScheduledExecutorService

ExecutorService executorService = ...
// 额外的处理,生成修饰了的对象executorService
executorService = TtlExecutors.getTtlExecutorService(executorService);

(3)核心就是,装饰之后,在执行子线程之前,会保存当前的线程Local的map
在子线程里面,会先恢复线程Local的Map,然后调用实际执行的run方法或call方法。

(4)注意,代码必须修改,使用TransmittableThreadLocal来保存值。
如果不能修改代码,比如第三方jar,人家还是使用原始的线程Local,则还是不能传递。
需要手动包装一下。


package xxx.yyy;

import org.slf4j.MDC;

import java.util.Map;
import java.util.concurrent.Callable;

public class MdcUtils {
    /**
     * 包装Runnable以传递MDC上下文
     */
    public static Runnable wrap(final Runnable runnable) {
        // 捕获当前MDC上下文
        final Map<String, String> context = MDC.getCopyOfContextMap();
        return new Runnable() {
            @Override
            public void run() {
                try {
                    if (context != null) {
                        MDC.setContextMap(context);
                    }
                    runnable.run();
                } finally {
                    MDC.clear();
                }
            }
        };
    }

    /**
     * 包装Callable以传递MDC上下文
     */
    public static <T> Callable<T> wrap(final Callable<T> callable) {
        // 捕获当前MDC上下文
        final Map<String, String> context = MDC.getCopyOfContextMap();
        return new Callable<T>() {
            @Override
            public T call() throws Exception {
                try {
                    if (context != null) {
                        MDC.setContextMap(context);
                    }
                    return callable.call();
                } finally {
                    MDC.clear();
                }
            }
        };
    }
}



executor.submit(MdcUtils.wrap(new Runnable() {
@Override
public void run() {

    System.out.println(Thread.currentThread().getName() + " - "+MDC.get("userId"));
}
}));
 

评论 COMMENTS
没有评论 No Comments.

添加评论 Add new comment.
昵称 Name:
评论内容 Comment:
验证码(不区分大小写)
Validation Code:
(not case sensitive)
看不清?点这里换一张!(Change it here!)
 
评论由管理员查看后才能显示。the comment will be showed after it is checked by admin.
CopyRight © 心缘地方 2005-2999. All Rights Reserved