多线程-父子线程传递参数

多线程-父子线程传递参数

场景

父子线程需要传递参数的场景有很多:

  • 分布式系统中链路追踪,获取调用链路上的 traceId
  • 日志系统中每个方法调用时上下文追踪,如 MDC

ThreadLocal

我们知道 ThreadLocal 可以解决在同一个线程的上下文传递参数,但是在多线程环境下,这显然就不行了

public class ThreadInherit {


    public static ThreadLocal<String> local = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {

        System.out.println("current Thread :" + Thread.currentThread().getName());
        local.set("hello");

        new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("task1.........");
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " context: " + local.get());

            }
        }).start();

        TimeUnit.MICROSECONDS.sleep(300);
        new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("task2.........");
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " context: " + local.get());

            }
        }).start();
    }
}

运行结果:

current Thread :main
task1.........
sub Thread :Thread-0 context: null
sub Thread :Thread-0 inherit context: world
task2.........
sub Thread :Thread-1 context: null
sub Thread :Thread-1 inherit context: world
phase1 current Thread :main inherit context: world

可以发现, ThreadLocal 并不能解决线程之间的上下文传递

InheritableThreadLocal

这个是 ThreadLocal 的子类, 可以在父子线程之间参数传递

public class ThreadInherit {


    public static ThreadLocal<String> local = new ThreadLocal<>();
    public static ThreadLocal<String> inheritLocal = new InheritableThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {

        System.out.println("current Thread :" + Thread.currentThread().getName());
        local.set("hello");
        inheritLocal.set("world");

        new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("task1.........");
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " context: " + local.get());
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " inherit context: " + inheritLocal.get());
                inheritLocal.set("task1");

            }
        }).start();

        TimeUnit.MICROSECONDS.sleep(300);
        new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("task2.........");
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " context: " + local.get());
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " inherit context: " + inheritLocal.get());

            }
        }).start();

        TimeUnit.SECONDS.sleep(2);
        System.out.println("phase1 current Thread :" + Thread.currentThread().getName() + " inherit context: " + inheritLocal.get());

     }
}

结果:

current Thread :main
task1.........
sub Thread :Thread-0 context: null
sub Thread :Thread-0 inherit context: world
task2.........
sub Thread :Thread-1 context: null
sub Thread :Thread-1 inherit context: world
phase1 current Thread :main inherit context: world

可以发现, InheritableThreadLocal 可以解决线程之间上下文传递

但是还有一种情况:

public class ThreadInherit {


    public static ThreadLocal<String> local = new ThreadLocal<>();
    public static ThreadLocal<String> inheritLocal = new InheritableThreadLocal<>();
    public static ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(1);

    public static void main(String[] args) throws InterruptedException {

        System.out.println("current Thread :" + Thread.currentThread().getName());
        local.set("hello");
        inheritLocal.set("world");

        new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("task1.........");
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " context: " + local.get());
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " inherit context: " + inheritLocal.get());
                inheritLocal.set("task1");

            }
        }).start();

        TimeUnit.MICROSECONDS.sleep(300);
        new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("task2.........");
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " context: " + local.get());
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " inherit context: " + inheritLocal.get());

            }
        }).start();

        TimeUnit.SECONDS.sleep(2);
        System.out.println("phase1 current Thread :" + Thread.currentThread().getName() + " inherit context: " + inheritLocal.get());

        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {

                System.out.println("task3......");
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " context: " + local.get());
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " inherit context: " + inheritLocal.get());
                inheritLocal.set("task3");
            }
        });

        TimeUnit.MICROSECONDS.sleep(300);
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {

                System.out.println("task4......");
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " context: " + local.get());
                System.out.println("sub Thread :" + Thread.currentThread().getName() + " inherit context: " + inheritLocal.get());
            }
        });


        TimeUnit.SECONDS.sleep(2);
        System.out.println("phase2 current Thread :" + Thread.currentThread().getName() + " inherit context: " + inheritLocal.get());
        TimeUnit.SECONDS.sleep(2);

    }
}

结果:

current Thread :main
task1.........
sub Thread :Thread-0 context: null
sub Thread :Thread-0 inherit context: world
task2.........
sub Thread :Thread-1 context: null
sub Thread :Thread-1 inherit context: world
phase1 current Thread :main inherit context: world
task3......
sub Thread :pool-1-thread-1 context: null
sub Thread :pool-1-thread-1 inherit context: world
task4......
sub Thread :pool-1-thread-1 context: null
sub Thread :pool-1-thread-1 inherit context: task3
phase2 current Thread :main inherit context: world

在线程池环境下,main thread 居然没有变成 task3, 这显然是不对的, 那如何解决呢?

TransmittableThreadLocal

TransmittableThreadLocal是阿里开源的一个组件,TransmittableThreadLocal 继承 InheritableThreadLocal,使用方式也类似,解决了在使用线程池等会池化复用线程的执行组件情况下传递ThreadLocal值的问题

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值