阿里TransmittableThreadLocal配合@Async使用过程

 更新时间:2026年02月04日 08:41:22   作者:蔚蓝色的咸鱼  
文章介绍了ThreadLocal、InheritableThreadLocal和TransmittableThreadLocal的区别,并通过实例展示了它们在不同场景下的使用方法

我们都知道ThreadLocal是可以在一个线程中当容器使用的局部变量,是线程隔离、线程安全的。

但是如果子线程要获取父线程的变量,便不太方便

我们分别来看ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal区别

一、ThreadLocal

线程池配置

@Slf4j
@EnableAsync
@Configuration
public class ThreadPoolConfig {

    @Bean
    public Executor testExecuteAsync(){
        ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
        poolExecutor.setCorePoolSize(5);
        poolExecutor.setMaxPoolSize(10);
        poolExecutor.setKeepAliveSeconds(10);
        poolExecutor.setQueueCapacity(60);
        poolExecutor.setThreadNamePrefix("testExecutor-");
        poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        poolExecutor.initialize();
        return poolExecutor;
    }
}

ThreadLocal工具类

public class ThreadLocalContext {

    private final static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static String get(){
        return threadLocal.get();
    }

    public static void set(String data){
        threadLocal.set(data);
    }

    public static void remove(){
        threadLocal.remove();
    }
}

测试service

@Service
@Slf4j
public class TestService {

    @Async("testExecuteAsync")
    public void test() throws InterruptedException {
        log.info("父线程内容:{}",ThreadLocalContext.get());
    }
}

测试类

@Test
    public void test1() throws InterruptedException {
        ThreadLocalContext.set("parent:" + Thread.currentThread().getName());
        for (int i = 0; i < 5; i++) {
            testService.test();
        }
        Thread.sleep(4000);
    }

运行结果

可以看到没有获取到父线程内容

二、InheritableThreadLocal

修改ThreadLocal工具类

public class ThreadLocalContext {

    private final static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();

    public static String get(){
        return threadLocal.get();
    }

    public static void set(String data){
        threadLocal.set(data);
    }

    public static void remove(){
        threadLocal.remove();
    }
}

运行程序

@Test
    public void test1() throws InterruptedException {
        ThreadLocalContext.set("parent:" + Thread.currentThread().getName());
        for (int i = 0; i < 5; i++) {
            testService.test();
        }
        Thread.sleep(4000);
    }

运行结果

这里是可以获取到父线程内容的

调整TestService代码

@Async("testExecuteAsync")
    public void test() throws InterruptedException {
        log.info("父线程内容:{}",ThreadLocalContext.get());
        //重新设置线程变量中的值
        ThreadLocalContext.set("child:" + Thread.currentThread().getName());
    }

运行代码

@Test
    public void test1() throws InterruptedException {
        ThreadLocalContext.set("parent:" + Thread.currentThread().getName());
        for (int i = 0; i < 5; i++) {
            testService.test();
        }
        Thread.sleep(4000);
        //第二次调用线程获取内容
        for (int i = 0; i < 5; i++) {
            testService.test();
        }
        Thread.sleep(4000);
    }

运行结果

三、TransmittableThreadLocal

修改线程池配置

注意其中的TtlExecutors.getTtlExecutor( poolExecutor)是使用TTL对线程池进行包裹

@Bean
    public Executor testExecuteAsync(){
        ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
        poolExecutor.setCorePoolSize(5);
        poolExecutor.setMaxPoolSize(10);
        poolExecutor.setKeepAliveSeconds(10);
        poolExecutor.setQueueCapacity(60);
        poolExecutor.setThreadNamePrefix("testExecutor-");
        poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        poolExecutor.initialize();
        return TtlExecutors.getTtlExecutor(poolExecutor);
    }

修改threadLocal工具类

public class ThreadLocalContext {

    private final static ThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();

    public static String get(){
        return threadLocal.get();
    }

    public static void set(String data){
        threadLocal.set(data);
    }

    public static void remove(){
        threadLocal.remove();
    }
}

运行结果

可以看到线程每次运行都是获取的父线程中的内容

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • JDK1.8安装与配置超详细教程

    JDK1.8安装与配置超详细教程

    JDK1.8即为JDK8,JDK8是目前是最成熟最稳定的版本,本文将详细介绍JDK1.8的安装与配置,需要的朋友可以参考下
    2023-03-03
  • Java实现银行账户管理子系统

    Java实现银行账户管理子系统

    这篇文章主要为大家详细介绍了Java实现银行账户管理子系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 一篇文章带你入门java工厂模式

    一篇文章带你入门java工厂模式

    这篇文章主要介绍了Java工厂模式,结合实例形式详细分析了java基本数据类型、数据类型转换、算术运算符、逻辑运算符等相关原理与操作技巧,需要的朋友可以参考下
    2021-08-08
  • 深入理解注解与自定义注解的一些概念

    深入理解注解与自定义注解的一些概念

    今天给大家带来的文章是注解的相关知识,本文围绕着注解与自定义注解的一些概念展开,文中详细介绍了这些知识,需要的朋友可以参考下
    2021-06-06
  • mybatis中的if test判断入参的值问题

    mybatis中的if test判断入参的值问题

    这篇文章主要介绍了mybatis中的if test判断入参的值问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Java中ArrayList和LinkedList的区别

    Java中ArrayList和LinkedList的区别

    ArrayList和LinkedList在这个方法上存在一定的性能差异,本文就介绍了Java中ArrayList和LinkedList的区别,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • 详解如何全注解方式构建SpringMVC项目

    详解如何全注解方式构建SpringMVC项目

    这篇文章主要介绍了详解如何全注解方式构建SpringMVC项目,利用Eclipse构建SpringMVC项目,非常具有实用价值,需要的朋友可以参考下
    2018-10-10
  • Java开发之手把手教你搭建企业级工程SSM框架

    Java开发之手把手教你搭建企业级工程SSM框架

    这篇文章主要为大家介绍Java教程中搭建企业级工程SSM框架,手把手的过程操作,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2021-09-09
  • 关于Java的ArrayList数组自动扩容机制

    关于Java的ArrayList数组自动扩容机制

    这篇文章主要介绍了关于Java的ArrayList数组自动扩容机制,ArrayList底层是基于数组实现的,是一个动态数组,自动扩容,不是线程安全的,只能用在单线程环境下,需要的朋友可以参考下
    2023-05-05
  • Spring Boot 整合 Apache Dubbo的示例代码

    Spring Boot 整合 Apache Dubbo的示例代码

    Apache Dubbo是一款高性能、轻量级的开源 Java RPC 框架,这篇文章主要介绍了Spring Boot 整合 Apache Dubbo的方法,本文通过示例说明给大家讲解的非常详细,需要的朋友可以参考下
    2021-07-07

最新评论