阿里开源的TransmittableThreadLocal的正确使用姿势

发布时间 2023-08-14 10:12:11作者: 甜菜波波

 

 

 目录

1. 直接使用 TransmittableThreadLocal

2. 在使用线程池的情况下使用 TransmittableThreadLocal

3. 使用 TtlExecutors 的使用案例 (推荐)

4. 拓展

 


 

                TransmittableThreadLocal是阿里巴巴开源的一个线程本地变量,它是ThreadLocal的一个增强版,可以在线程池等多线程环境下使用,解决了ThreadLocal在多线程环境下的一些问题。

在多线程环境下,ThreadLocal可以避免线程安全问题,但是在使用线程池等多线程环境时,ThreadLocal可能会出现一些问题。例如,当使用线程池时,线程池中的线程可能会被多个任务共享,如果使用ThreadLocal存储数据,可能会导致数据被错误地共享。

        TransmittableThreadLocal解决了这个问题,它可以在多线程环境下正确地传递数据。具体来说,当一个线程从线程池中获取到一个线程时,TransmittableThreadLocal会自动将当前线程的ThreadLocal副本传递给新的线程,从而保证数据的正确性。

        下面有几个简单的示例,演示了如何使用TransmittableThreadLocal

 

1. 直接使用 TransmittableThreadLocal

  1.  
    public class TransmittableThreadLocalDemo {
  2.  
    private static TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
  3.  
     
  4.  
    public static void main(String[] args) {
  5.  
    // 在主线程中设置TransmittableThreadLocal的值
  6.  
    threadLocal.set("Hello, World!");
  7.  
     
  8.  
    // 在新线程中获取TransmittableThreadLocal的值
  9.  
    Thread thread = new Thread(() -> {
  10.  
    String value = threadLocal.get();
  11.  
    System.out.println("TransmittableThreadLocal value in new thread: " + value);
  12.  
    });
  13.  
    thread.start();
  14.  
    }
  15.  
    }

        在这个示例中,我们首先在主线程中将一个字符串存储到TransmittableThreadLocal中。然后,我们创建一个新线程,在新线程中获取TransmittableThreadLocal的值并打印出来。由于TransmittableThreadLocal可以正确地传递数据,因此新线程中获取到的值与主线程中设置的值是相同的。

        需要注意的是,TransmittableThreadLocal是ThreadLocal的一个增强版,因此在使用时需要注意一些细节。例如,TransmittableThreadLocal的使用方式与ThreadLocal略有不同,需要使用TtlRunnable和TtlCallable等类来包装Runnable和Callable。此外,TransmittableThreadLocal也需要进行垃圾回收,否则可能会导致内存泄漏

 

2. 在使用线程池的情况下使用 TransmittableThreadLocal

        在使用线程池的情况下,如果需要使用TransmittableThreadLocal,可以使用阿里巴巴的TTL库来实现。TTL库提供了一些工具类,可以方便地在使用线程池的情况下使用TransmittableThreadLocal。

        具体来说, 可以使用TtlRunnable和TtlCallable等类来包装 Runnable 和 Callable,从而在执行任务时自动传递ThreadLocal的值。例如,下面是一个使用线程池和TransmittableThreadLocal的示例:

  1.  
    public class ThreadPoolDemo {
  2.  
    private static TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
  3.  
     
  4.  
    public static void main(String[] args) throws InterruptedException {
  5.  
    ExecutorService executorService = Executors.newFixedThreadPool(2);
  6.  
     
  7.  
    // 在主线程中设置TransmittableThreadLocal的值
  8.  
    threadLocal.set("Hello, World!");
  9.  
     
  10.  
    // 在线程池中执行任务
  11.  
    executorService.execute(TtlRunnable.get(() -> {
  12.  
    String value = threadLocal.get();
  13.  
    System.out.println("TransmittableThreadLocal value in new thread: " + value);
  14.  
    }));
  15.  
     
  16.  
    // 等待任务执行完成
  17.  
    executorService.shutdown();
  18.  
    executorService.awaitTermination(1, TimeUnit.SECONDS);
  19.  
    }
  20.  
    }

        在这个示例中,我们首先创建了一个线程池,然后在主线程中设置了一个TransmittableThreadLocal的值。接着,我们使用TtlRunnable包装了一个Runnable任务,并将其提交到线程池中执行。在执行任务时,TtlRunnable会自动传递ThreadLocal的值,从而保证了数据的正确性


3. 使用 TtlExecutors 的使用案例 (推荐)

        TtlExecutors是阿里巴巴开源的一个工具类,用于在使用线程池的情况下使用TransmittableThreadLocal。具体来说,TtlExecutors提供了一些工具方法,可以方便地将线程池和TransmittableThreadLocal结合起来使用。

下面是一个使用TtlExecutors的示例代码:        

  1.  
    import com.alibaba.ttl.TransmittableThreadLocal;
  2.  
    import com.alibaba.ttl.threadpool.TtlExecutors;
  3.  
     
  4.  
    import java.util.concurrent.ExecutorService;
  5.  
    import java.util.concurrent.Executors;
  6.  
     
  7.  
    public class TtlExecutorsDemo {
  8.  
    private static TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
  9.  
     
  10.  
    public static void main(String[] args) {
  11.  
    // 创建一个固定大小的线程池
  12.  
    ExecutorService executorService = Executors.newFixedThreadPool(2);
  13.  
     
  14.  
    // 在主线程中设置TransmittableThreadLocal的值
  15.  
    threadLocal.set("Hello, World!");
  16.  
     
  17.  
    // 使用TtlExecutors包装线程池
  18.  
    ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(executorService);
  19.  
     
  20.  
    // 提交任务到线程池中
  21.  
    ttlExecutorService.submit(() -> {
  22.  
    String value = threadLocal.get();
  23.  
    System.out.println("Task is running in thread: " + Thread.currentThread().getName() + ", TransmittableThreadLocal value: " + value);
  24.  
    });
  25.  
     
  26.  
    // 关闭线程池
  27.  
    ttlExecutorService.shutdown();
  28.  
    }
  29.  
    }

        
        在这个示例中,我们首先创建了一个固定大小的线程池,并在主线程中设置了一个TransmittableThreadLocal的值。接着,我们使用TtlExecutors.getTtlExecutorService()方法将线程池包装成一个支持TransmittableThreadLocal的线程池。最后,我们使用包装后的线程池提交了一个任务,并在任务中获取了TransmittableThreadLocal的值

4. 拓展

        除了在使用线程池的情况下使用TransmittableThreadLocal外,还有一些其他的使用案例。

例如,在使用Dubbo等分布式框架时,TransmittableThreadLocal可以用于在服务调用链路中传递数据。具体来说,可以在服务提供者和消费者中使用TransmittableThreadLocal来传递一些上下文信息,例如请求ID、用户信息等。这样可以方便地在服务调用链路中获取这些信息,从而实现一些功能,例如日志追踪、权限校验等。

另外,TransmittableThreadLocal还可以用于一些需要在多个线程之间共享数据的场景。例如,在使用Netty等网络编程框架时,可以使用TransmittableThreadLocal来在不同的事件处理器之间共享一些上下文信息,例如连接信息、请求信息等。

总之,TransmittableThreadLocal可以用于在多线程环境下传递数据,解决了ThreadLocal在多线程环境下的一些问题。在使用TransmittableThreadLocal时需要注意一些细节,例如需要进行垃圾回收等。同时,也需要根据具体的使用场景来选择合适的使用方式。

 

转自:https://blog.csdn.net/m0_51681531/article/details/130424028