TransmittableThreadLocal使用与详解

1.TransmittableThreadLocal介绍

TransmittableThreadLocal 是 Alibaba 开源的一个库,旨在解决在多线程环境中正确处理 ThreadLocal的问题。它提供了一个能够在线程间传递 ThreadLocal 值的特性。

1.1ThreadLocal

ThreadLocal 是 Java 中的一个线程级别的变量,它提供了一种线程私有的变量存储机制。每个线程都有自己独立的 ThreadLocal 实例,可以用于在线程内部存储和获取数据,而不会与其他线程共享。

  1. 线程隔离的变量存储:
    ThreadLocal 提供了一种在线程内部存储变量的机制。通过 ThreadLocal,每个线程都可以拥有自己独立的变量副本,这些变量副本在其他线程中不可见,实现了线程之间的数据隔离。
  2. 数据存取操作:
    ThreadLocal 提供了一些方法来存储和获取变量的值,包括:
    set(T value):将变量的值设置为指定值。
    get():获取当前线程的变量值。
    remove():从当前线程中删除变量。
  3. 线程切换的变量连续性:
    当线程切换时,ThreadLocal 可以保持变量的连续性。也就是说,新线程可以继续访问之前线程存储的变量值。这在一些场景下非常有用,例如使用线程池时,任务在不同的线程中执行,但仍然需要访问之前线程中存储的上下文信息。
  4. 避免线程间的共享和竞争条件:
    由于每个线程拥有自己的 ThreadLocal 实例,因此变量的存取不会引起线程之间的竞争条件。每个线程都可以独立地存取自己的变量副本,不需要使用同步机制来保护变量的访问。

需要注意的是,尽管 ThreadLocal 提供了一种在线程内部存储变量的机制,但它并不适合在所有情况下使用。过度使用 ThreadLocal 可能导致内存泄漏或引起上下文信息的错误传递。在使用 ThreadLocal 时,需要仔细评估和测试代码,确保正确使用和管理变量的生命周期。

在 Java 中,ThreadLocal 是作为一个类提供的,位于 java.lang 包中。可以使用 ThreadLocal 类的实例来创建线程级别的变量,并使用其提供的方法进行操作。

1.2使用场景

在传统的多线程环境中,ThreadLocal 变量是线程私有的,即每个线程都有自己独立的 ThreadLocal 值。然而,在一些特定场景下,我们希望在线程切换时能够传递 ThreadLocal 值,以保持特定线程的上下文信息的连续性。这就是 TransmittableThreadLocal 的用武之地。

2.使用

2.1引入依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>transmittable-thread-local</artifactId>
    <version>2.13.0</version>
</dependency>

2.2 创建 TransmittableThreadLocal 实例:

private static ThreadLocal<String> myThreadLocal = new TransmittableThreadLocal<>();
//TransmittableThreadLocal<>支持传入不同数据结构
private static final TransmittableThreadLocal<Map<String, Object>> inheritableThreadLocal = new TransmittableThreadLocal<>();

2.3 设置和获取值

//String
myThreadLocal.set("Hello, World!");
String value = myThreadLocal.get();
//Map
Map<String, Object> threadMap = new HashMap<>();
threadMap.put("userinfo", ssoUserInfo);
threadMap.put("referer", referer);
inheritableThreadLocal.set(threadMap);

2.4 线程切换时传递值:

当线程切换时,TransmittableThreadLocal 可以自动将当前线程的 ThreadLocal 值传递给新的线程。这样,新线程可以继续使用之前线程的上下文信息。例如,使用线程池时,当任务从一个线程切换到另一个线程时,TransmittableThreadLocal 可以保持 ThreadLocal 值的连续性。

需要注意的是,TransmittableThreadLocal 并非是 Java 标准库中的类,它是 Alibaba 开源的一个扩展库,为了解决 ThreadLocal 在跨线程传递值时的问题而设计。在使用 TransmittableThreadLocal 时,需要确保代码中正确引入了该库,并替换相应的 ThreadLocal 实例。

使用 TransmittableThreadLocal 需要谨慎,因为它在某些情况下可能导致内存泄漏或上下文信息的错误传递。需要仔细评估和测试代码,确保正确处理 ThreadLocal 值的传递,并避免潜在的问题。

3.原理

  1. 初始线程设置值:

    在初始线程中,当调用 TransmittableThreadLocalset() 方法设置 ThreadLocal 的值时,实际上会将值存储在一个全局的映射表中,以线程 ID 为键,值为 ThreadLocal 的值。

            @Override
        public final void set(T value) {
            super.set(value);
            // may set null to remove value
            if (null == value) removeValue();
            else addValue();
        }
    
        @Override
        public final T get() {
            T value = super.get();
            if (null != value) addValue();
            return value;
        }
    
    
    	private void addValue() {
            if (!holder.get().containsKey(this)) {
                holder.get().put(this, null); // WeakHashMap supports null value.
            }
    	}
    
    	//使用 InheritableThreadLocal 类创建了一个实例 holder。InheritableThreadLocal 是 ThreadLocal 的子类,它允许在父线程和子线程之间传递值。
        private static InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>> holder =
                new InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>>() {
            		//通过重写 initialValue() 方法,定义了在初始线程中创建的映射表对象。这个映射表使用 WeakHashMap 来存储 TransmittableThreadLocal 实例和对应的值。WeakHashMap 的使用可以避免造成内存泄漏,因为它使用弱引用来保存键,当键不再被其他引用持有时,将会被垃圾回收。
                    @Override
                    protected Map<TransmittableThreadLocal<?>, ?> initialValue() {
                        return new WeakHashMap<TransmittableThreadLocal<?>, Object>();
                    }
    				//通过重写 childValue() 方法,定义了在子线程中创建的映射表对象。这个方法接收父线程中的映射表对象作为参数,并通过构造一个新的 WeakHashMap 对象来创建子线程的映射表。由于 WeakHashMap 是基于弱引用的,它会继承父线程的映射表并在需要时进行垃圾回收。
                    @Override
                    protected Map<TransmittableThreadLocal<?>, ?> childValue(Map<TransmittableThreadLocal<?>, ?> parentValue) {
                        return new WeakHashMap<TransmittableThreadLocal<?>, Object>(parentValue);	
                    }
                };
    
    
  2. 线程切换时传递值:

    当线程发生切换时,例如使用线程池或线程复用机制时,新的线程被分配或复用,原始线程的 ThreadLocal 值将被传递给新的线程。

  3. 新线程获取值:

    在新的线程中,当调用 TransmittableThreadLocalget() 方法获取 ThreadLocal 的值时,它首先会获取当前线程的线程 ID,并通过全局映射表查找原始线程的 ThreadLocal 值。

  4. 内存清理和释放:

    TransmittableThreadLocal 会根据线程的生命周期进行相应的内存清理和释放。当线程完成后,相关的 ThreadLocal 值将被清理,并且不会影响其他线程。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
@KafkaListener是Spring Kafka提供的注解,用于标识一个方法作为Kafka消息的监听器。它可以与其他注解一起使用,以配置和定制监听器的行为。 @KafkaListener注解的用法如下所示: - id属性用于指定监听器的唯一标识符。 - idIsGroup属性用于指定id是否作为消费者组的一部分。 - topics属性用于指定监听的主题。 - containerFactory属性用于指定用于创建监听容器的工厂。 - concurrency属性用于指定并发消费者的数量。 - clientIdPrefix属性用于指定消费者的客户端ID前缀。 - groupId属性用于指定消费者组的ID。 - properties属性用于指定其他Kafka消费者的属性。 - errorHandler属性用于指定错误处理器。 除了基本的用法外,@KafkaListener还可以与其他注解一起使用,以进一步定制监听器的行为。例如,可以使用@Payload注解指定消息的有效负载类型,以及使用@Valid注解验证有效负载对象。 要使用@KafkaListener注解,您需要在Spring Kafka配置类中添加@Bean注解来创建KafkaListenerContainerFactory bean,并在您的监听器方法上添加@KafkaListener注解。 您还可以使用KafkaListenerEndpointRegistry来获取已注册的所有监听器容器。这可以在需要动态管理和操作监听器时非常有用。 总结起来,@KafkaListener注解提供了一个方便的方式来创建Kafka消息的监听器,并可以使用各种属性和其他注解来定制它们的行为。同时,使用KafkaListenerEndpointRegistry可以方便地管理和操作已注册的监听器容器。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [@KafkaListener详解使用](https://blog.csdn.net/h4241778/article/details/122416366)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【spring-kafka】@KafkaListener详解使用](https://blog.csdn.net/u010634066/article/details/109803987)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值