• ThreadLocal InheritableThreadLocal TransmittableThreadLocal简单使用


    需求: 主线程向异步线程传递用户token信息,

    关于线程之间数据传递的几个关键对象,

    • 主线程向子线程传递时,可以通过InheritableThreadLocal对象
    • 使用ExecutorService或者CompletableFuture执行时, 线程池内线程复用的原因,同时Thread对象内的inheritableThreadLocals值一是null,所以无法使用InheritableThreadLocal对象
    • TransmittableThreadLocal为比较适合解决方案 官方地址
    • 异步线程RequestContextHolder为空问题

    先上例子

    public static final ThreadLocal<String> context = new ThreadLocal<>();//
    public static final ThreadLocal<String> context1 = new TransmittableThreadLocal<>();//
    public static final ThreadLocal<String> context2 = new InheritableThreadLocal<>();
    
    public static void main(String[] args) {
            context.set("A");
            context1.set("B");
            context2.set("C");
            CompletableFuture.runAsync(() -> {//ThreadLocal 线程之间隔离
                String mm = context.get();
                log.info("1: {}",mm);
            });
            CompletableFuture.runAsync(TtlRunnable.get(() -> { //TransmittableThreadLocal可以取到
                String mm = context1.get();
                log.info("2: {}",mm);
    
            }));
            CompletableFuture.runAsync(() -> { //取不到
                String mm = context2.get();
                log.info("3: {}",mm);
    
            });
            Thread thread = new Thread(() -> { // 子线程,正常可以取到
                String mm = context2.get();
                log.info("4: {}",mm);
            });
            thread.start();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    [ForkJoinPool.commonPool-worker-1] INFO cn.me56.integration.stat.StatApiController - 1: null
    [ForkJoinPool.commonPool-worker-2] INFO cn.me56.integration.stat.StatApiController - 2: A
    [ForkJoinPool.commonPool-worker-1] INFO cn.me56.integration.stat.StatApiController - 3: null
    [Thread-0] INFO cn.me56.integration.stat.StatApiController - 4: C
    
    • 1
    • 2
    • 3
    • 4

    这里是InheritableThreadLocal使用子线程的例子:

    public class InheritableThreadLocalDemo {
    
        private static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
    
        public static void main(String[] args) {
            threadLocal.set("mainThread");
            System.out.println("value:"+threadLocal.get());
            Thread thread = new Thread(new Runnable() { //子线程,可以取到
                @Override
                public void run() {
                    String value = threadLocal.get();
                    System.out.println("value:"+value);
                }
            });
            thread.start();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    value:mainThread
    value:mainThread
    
    • 1
    • 2

    TransmittableThreadLocal,简单使用方法

    public static final ThreadLocal<String> context1 = new TransmittableThreadLocal<>();//
    CompletableFuture.runAsync(TtlRunnable.get(() -> { 
    	//do something...
    }));
    或者
    CompletableFuture.supplyAsync(TtlWrappers.wrapSupplier(()-> {
    	//do something...
    	return "return value";
    	}) );
    或者
    java agent 方式 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    线程之间可以传递数据之后,再看下RequestContextHolder为空问题, 初步是想把request对象传给异步线程, 尝试之后觉得此方案不合理,没必要把整个request传进去

    1. 使用如下方式.设置之后,进入异步线程,RequestContextHolder.getRequestAttributes()也还是空的…
    RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);
    
    • 1
    1. 如下使用如下方式.在主线程关闭之后,子线程想获取request内参数,还是空的,如果是copy一个request,应该就能正常了
    CompletableFuture.runAsync(() -> { 
    	RequestContextHolder.setRequestAttributes(...);
    	//do something...
    });
    
    • 1
    • 2
    • 3
    • 4

    最终,因为业务需要完成的,是希望把长时间统计/查询接口,在系统资源有限的情况下,以时间换空间,拆分成多个子任务,所以这里线程之间传参仅仅只用了MDC.put/get方式简单实现了一下

  • 相关阅读:
    Azure + React + ASP.NET Core 项目笔记一:项目环境搭建(二)
    程序人生——Java中类、对象及方法的建议(1)
    【神经网络】CNN网络:深入理解卷积神经网络
    【Proteus仿真】【STM32单片机】自动饲养控制系统
    查看docker 容器的端口
    SpringBoot中Bean的条件装配
    (11)组合设计模式
    【免杀前置课——Windows编程】十三、事件与信号量——事件与互斥体区别、操纵信号量实现游戏多开访问控制(附代码)
    Scrapy第二篇:构建scrapy项目
    快速上手thymeleaf
  • 原文地址:https://blog.csdn.net/zoeou/article/details/127818532