TTL TransmittableThreadLocal使用示例

TTL 线程间可传递线程本地存储

作用:在新创建的子线程时,希望继承父线程ThreadLocal设置的对象,继续使用。

场景:

  1. 最典型的 监控或日志系统实现接口调用链中traceid的传递,通过traceid串联整个调用链路的日志。
  2. 可用于解决多线程不能共享事务的问题。

和InheritableThreadLocal的区别:InheritableThreadLocal 的目的一样,但对线程池的支持不好。实际开发过程中很少手动new Thread的方式创建线程,初始化线程池的的线程为线程池中线程的父线程,现实场景调用线程池的用户线程与 线程池中的线程是没有一点关系的,用户线程调用线程池,一般只是把任务丢到线程池的任务队列(线程池中的线程可能是由其他用户线程创建的,核心线程创建后是一直复用的),所以线程的父子关系可能不成立 ,这样用户线程中的ThreadLocal可能就传递不过去。但TransmittableThreadLocal可以,这就是他们最明示的区别。

技术最快的入门方法就是自己实际使用测试一下:

import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.threadpool.TtlExecutors;
import lombok.Data;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TransmittableThreadLocalTest {

    // 用ExecutorServiceTtlWrapper 代理 ThreadPoolExecutor
    private static ExecutorService executorService =
            TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(2));

    // TTL
    private static ThreadLocal<LocalBean> ttl = new TransmittableThreadLocal();

    public static void main(String[] args) {
        LocalBean localBean = new LocalBean("init string value");
        ttl.set(localBean); // 在主线程设置初始值
        new Thread(() -> {
            System.out.println("对普通线程的传递性:" + ttl.get());
            localBean.setProp("new thread value");
        }).start();
        // 1、线程池中取值,设置对象内的属性值,测试是否影响外部线程
        executorService.execute(() -> {
            LocalBean localBean1 = ttl.get();
            System.out.println(String.format("TTL(%s): %s", Thread.currentThread().getName(), localBean1.getProp()));
            localBean1.setProp(String.format("TTL set in Pool(%s)", Thread.currentThread().getName()));
            System.out.println(String.format("After set TTL(%s): %s", Thread.currentThread().getName(), ttl.get().getProp()));
        });

        sleep(100);
        System.out.println(String.format("Main TTL(%s): %s", Thread.currentThread().getName(), ttl.get().getProp()));
        // 2、修改对象引用,测试是否影响外部线程
        executorService.execute(() -> {
            System.out.println(String.format("TTL(%s): %s", Thread.currentThread().getName(), ttl.get().getProp()));
            ttl.set(new LocalBean("Modify reference in thread pool"));
        });

        sleep(100);
        System.out.println(String.format("main TTL(%s): %s", Thread.currentThread().getName(), ttl.get()));
    }

    private static void sleep(long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Data
    static class LocalBean {
        private String prop;

        LocalBean(String p) {
            this.prop = p;
        }
    }
}

输出结果如下 :

对普通线程的传递性:TransmittableThreadLocalTest.LocalBean(prop=init string value)
TTL(pool-1-thread-1): new thread value
After set TTL(pool-1-thread-1): TTL set in Pool(pool-1-thread-1)
Main TTL(main): TTL set in Pool(pool-1-thread-1)
TTL(pool-1-thread-2): TTL set in Pool(pool-1-thread-1)
main TTL(main): TransmittableThreadLocalTest.LocalBean(prop=TTL set in Pool(pool-1-thread-1))

这张图描述了Thread、InheritableThreadlocal、TransmittableThreadLocal三者的关系,及 他们各自实现线程间ThreadLocal传递的基本原理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值