如何在子线程拿到父线程threadLocal的值

ThreadLocal父子线程数据传递?

(面试题:如何在子线程拿到父线程threadLocal的值)

1、演示子线程无法拿到值
    /**
     * 直接使用ThreadLocal,无法获得父线程的值
     */
    public static void demo1() {
        ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
        stringThreadLocal.set("今天星期五");
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + stringThreadLocal.get());//Thread-0null
        }).start();
        System.out.println(Thread.currentThread().getName() + "执行完成");
    }
2、使用InheritableThreadLocal解决
    /**
     * 使用InheritableThreadLocal,可以拿到父线程的值,
     * 原理:在线程init方法时传入父线程的threadLocal
     */
    public static void demo2() {
        ThreadLocal<String> stringThreadLocal = new InheritableThreadLocal<>();
        stringThreadLocal.set("今天星期五");
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()
                               + stringThreadLocal.get());//Thread-0今天星期五
        }).start();
        System.out.println(Thread.currentThread().getName() + "执行完成");
    }
3、带来的问题:在线程池中只能获取初始化线程时父线程的值
 /**
     * 在线程池使用InheritableThreadLocal,因为线程池中的线程是重复利用的,只能拿到线程init时父线程ThreadLocal的值
     *
     * @throws InterruptedException
     */
    public static void demo3() throws InterruptedException {
        InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
        ExecutorService threadPool = Executors.newFixedThreadPool(1);
        threadLocal.set("首次赋值");
        Semaphore semaphore = new Semaphore(1);
        threadPool.submit(() -> {
            System.out.println(Thread.currentThread().getName() + threadLocal.get());
        });
        semaphore.acquire();
        threadLocal.set("再次赋值");
        threadPool.submit(() -> {
            semaphore.release();
            System.out.println(Thread.currentThread().getName() 
            + threadLocal.get());//还是初值
        });
        semaphore.acquire();
        threadPool.shutdown();
    }
4、解决:使用阿里开源工具类**transmittable-thread-local**

通过装饰类调用前重新将父线程的值进行赋值

 /**
     * 注意:
     * 即使是同一个Runnable任务多次提交到线程池时,
     * 每次提交时都需要通过修饰操作(即TtlRunnable.get(task))以抓取这次提交时的
     * TransmittableThreadLocal上下文的值;
     * 即如果同一个任务下一次提交时不执行修饰而仍然使用上一次的TtlRunnable,
     * 则提交的任务运行时会是之前修饰操作所抓取的上下文。
     *
     * @throws InterruptedException
     */
    public static void demo4() throws InterruptedException {
        TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
        ExecutorService threadPool = Executors.newFixedThreadPool(1);
        threadLocal.set("首次赋值");
        Semaphore semaphore = new Semaphore(1);
        // 额外的处理,生成修饰了的对象ttlRunnable
        Runnable task = TtlRunnable.get(() -> {
            System.out.println(Thread.currentThread().getName() + threadLocal.get());
        });
        threadPool.submit(task);//pool-1-thread-1首次赋值
        semaphore.acquire();
        threadLocal.remove();
        threadLocal.set("再次赋值");
        // 额外的处理,生成修饰了的对象ttlCallable
        Runnable task2 = TtlRunnable.get(() -> {
            System.out.println(Thread.currentThread().getName() + threadLocal.get());
        });
        threadPool.submit(task2);//pool-1-thread-1再次赋值
        semaphore.acquire();
        threadPool.shutdown();
    }
5、解决2:通过线程池包装类解决
   /**
     * 修饰线程池
     * 省去每次Runnable和Callable传入线程池时的修饰,这个逻辑可以在线程池中完成。
     *
     * @throws InterruptedException
     */
    public static void demo5() throws InterruptedException {
        TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        ExecutorService threadPool = TtlExecutors.getTtlExecutorService(executorService);
        threadLocal.set("首次赋值");
        Semaphore semaphore = new Semaphore(1);
        threadPool.submit(() -> {
            System.out.println(Thread.currentThread().getName() + threadLocal.get());
        });
        semaphore.acquire();
        threadLocal.set("再次赋值");
        threadPool.submit(() -> {
            semaphore.release();
            System.out.println(Thread.currentThread().getName() + threadLocal.get());//pool-1-thread-1再次赋值
        });
        semaphore.acquire();
        threadPool.shutdown();
    }

附:maven地址

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>transmittable-thread-local</artifactId>
            <version>2.12.6</version>
        </dependency>
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值