Thread Local六连问,你扛得住吗?

2024-06-05 01:52

本文主要是介绍Thread Local六连问,你扛得住吗?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、Thread Local 是什么?

线程本地变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立地改变自己的副本,而不影响其他线程,做到了线程隔离。

二、Thread Local 的实现原理是什么?
ThreadLocal原理 · 进击的java菜鸟

ThreadLocal有一个静态内部类ThreadLocalMap, ThreadLocalMap又包含一个Entry数组,Entry本身是一个弱引用,它的key是指向ThreadLocal的弱引用,Entry具备了保存key value键值对的能力。弱引用的目的是为了防止内存泄漏,如果是强引用那么ThreadLocal对象除非线程结束否则无法被回收,弱引用则会在下一次GC的时候被回收。

但是这样还是会存在内存泄露的问题,假如key和ThreadLocal对象被回收之后,entry中就存在key为null,但是value有值的entry对象,但是永远没办法被访问到,同样除非线程结束运行。但是只要ThreadLocal使用恰当,在使用完之后调用remove方法删除Entry对象,实际上是不会出现这个问题的。

ThreadLocal 是一个线程的本地变量,也就意味着这个变量是线程独有的,是不能与其他线程共享的,这样就可以避免资源竞争带来的多线程的问题,这种解决多线程的安全问题和lock(这里的lock 指通过synchronized 或者Lock 等实现的锁) 是有本质的区别的:

  1. lock 的资源是多个线程共享的,所以访问的时候需要加锁。
  2. ThreadLocal 是每个线程都有一个副本,是不需要加锁的。
  3. lock 是通过时间换空间的做法。
  4. ThreadLocal 是典型的通过空间换时间的做法。

三、Thread Local 有什么作用?

ThreadLocal的作用是提供线程内的局部变量,在多线程环境下访问时能保证各个线程内的ThreadLocal变量各自独立。 也就是说,每个线程的ThreadLocal变量是自己专用的,其他线程是访问不到的。

四、Thread Local 如何使用?

Thread Local 的使用方法是通过 ThreadLocal 类创建一个 ThreadLocal 对象,并通过设置和获取方法来操作其中的变量副本。在线程中通过调用 set 方法可以设置当前线程的变量副本的值,在其他地方通过 get 方法可以获取当前线程的变量副本的值。

定义了一个 ThreadLocal 变量 threadLocal,它的泛型类型是 Integer。然后创建了两个线程,并分别启动它们。每个线程都会执行一个 Runnable 实现类 MyRunnable,在这个类中,使用了 ThreadLocal 来保存每个线程的局部变量值,并在 run 方法中进行设置、获取和清除操作。

通过这个示例,可以看到不同线程之间的局部变量互不干扰,每个线程都可以独立地访问和修改自己的局部变量值,而不会影响其他线程。

public class ThreadLocalExample {// 定义一个 ThreadLocal 变量private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();public static void main(String[] args) {// 创建两个线程,并启动Thread thread1 = new Thread(new MyRunnable("Thread-1"));Thread thread2 = new Thread(new MyRunnable("Thread-2"));thread1.start();thread2.start();}static class MyRunnable implements Runnable {private String name;public MyRunnable(String name) {this.name = name;}@Overridepublic void run() {// 设置当前线程的局部变量值threadLocal.set((int) (Math.random() * 100));// 获取当前线程的局部变量值并打印System.out.println("Thread " + name + " ThreadLocal value: " + threadLocal.get());// 清除当前线程的局部变量值threadLocal.remove();}}
}

五、Thread Local 有哪些常见使用场景?

  • 线程安全的对象存储: 在多线程环境中,有时候需要每个线程都拥有自己的对象实例,以避免线程安全问题。ThreadLocal 可以用来存储线程私有的对象实例,每个线程都可以独立地访问自己的对象实例,而不会受到其他线程的影响。

  • Web 应用中的用户身份信息传递: 在 Web 应用中,用户的身份信息通常会在多个组件或层之间传递,例如在拦截器、过滤器、Servlet、Spring MVC 控制器等中。使用 ThreadLocal 可以方便地将用户身份信息存储在当前线程中,在整个请求处理过程中都可以方便地获取到用户身份信息,而不必在每个方法参数中传递。

  • 数据库连接管理: 在需要频繁地访问数据库的应用中,为了提高性能通常会使用连接池管理数据库连接。ThreadLocal 可以用来存储线程私有的数据库连接,保证每个线程都能够独立地获取自己的数据库连接,而不会出现多线程并发访问数据库连接的问题。

  • 事务管理: 在使用事务进行数据库操作时,通常会将事务与当前线程进行绑定,以确保在同一个事务中执行的多个数据库操作能够在同一个事务上下文中进行。ThreadLocal 可以用来存储当前线程的事务上下文,保证每个线程都能够独立地获取自己的事务上下文,而不会影响其他线程的事务操作。

  • 线程上下文信息传递: 在某些情况下,需要在线程之间传递一些上下文信息,例如请求标识、日志跟踪信息等。ThreadLocal 可以用来存储线程私有的上下文信息,每个线程都可以独立地获取自己的上下文信息,而不会影响其他线程。

六、Thread Local 有哪些注意事项?

  1. 内存泄漏:要及时清理不再需要的 Thread Local 变量,避免长时间持有对对象的引用导致内存泄漏。
  2. 并发安全:尽量避免在多个线程之间共享可变状态的 Thread Local 变量,以确保线程安全。
  3. 全局状态:过度使用 Thread Local 可能会导致程序变得难以理解和维护,应该谨慎使用,并考虑是否有更好的解决方案。
  4. 性能影响:大量的 Thread Local 变量可能会增加线程间切换的开销,需要权衡使用场景和性能影响。

这篇关于Thread Local六连问,你扛得住吗?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1031741

相关文章

大数据spark3.5安装部署之local模式详解

《大数据spark3.5安装部署之local模式详解》本文介绍了如何在本地模式下安装和配置Spark,并展示了如何使用SparkShell进行基本的数据处理操作,同时,还介绍了如何通过Spark-su... 目录下载上传解压配置jdk解压配置环境变量启动查看交互操作命令行提交应用spark,一个数据处理框架

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

Thread如何划分为Warp?

1 .Thread如何划分为Warp? https://jielahou.com/code/cuda/thread-to-warp.html  Thread Index和Thread ID之间有什么关系呢?(线程架构参考这里:CUDA C++ Programming Guide (nvidia.com)open in new window) 1维的Thread Index,其Thread

RT-Thread(Nano版本)的快速移植(基于NUCLEO-F446RE)

目录 概述 1 RT-Thread 1.1 RT-Thread的版本  1.2 认识Nano版本 2 STM32F446U上移植RT-Thread  2.1 STM32Cube创建工程 2.2 移植RT-Thread 2.2.1 安装RT-Thread Packet  2.2.2 加载RT-Thread 2.2.3 匹配相关接口 2.2.3.1 初次编译代码  2.2.3.

GTK中创建线程函数g_thread_new和g_thread_create的区别

使用GThread函数,需要引用glib.h头文件。 这两个接口的核心区别就是  g_thread_create 是旧的接口,现在已经不使用了,而g_thread_new是新的接口,建议使用。 g_thread_create: g_thread_create has been deprecated since version 2.32 and should not be used in n

Android studio jar包多层嵌套,Add library '__local_aars__:...@jar' to classpath问题

在添加jar包,早app下的build.gradle中的 implementation files('libs/jar包的名字.jar') 修改为 api files('libs/jar包的名字.jar') implementation 单层引用,只引用当前jar包层, api 多层引用,应用当前jar包层,已经jar包引用的jar包层

基于 rt-thread的I2C操作EEPROM(AT24C02)

一、AT24C02 The AT24C01A/02/04/08A/16A provides 1024/2048/4096/8192/16384 bits of serial electrically erasable and programmable read-only memory (EEPROM) organized as 128/256/512/1024/2048 words of 8 b

[项目][CMP][Thread Cache]详细讲解

目录 1.设计&结构2.申请内存3.释放内存4.框架 1.设计&结构 Thread Cache是哈希桶结构,每个桶是一个按桶位置映射大小的内存块对象的自由链表 每个线程都会有一个Thread Cache对象,这样每个线程在这里获取对象和释放对象时是无锁的 TLS – Thread Local Strorage Linux gcc下TLSWindows vs下TLS

线程池工具类——Thread学习笔记

记录一下线程池工具类: /*** 线程池工具类* @author lixiang* @date 2018年10月10日 - 11:10* @history 2018年10月10日 - 11:10 lixiang create.*/public class ThreadPoolHelper {private static final Logger logger = LoggerFactory.g

模拟线程死锁——Thread学习笔记

记录一下之前写过的一段模拟死锁的代码: /*** 模拟死锁** @author lixiang* @date 2018年10月12日 - 9:51* @history 2018年10月12日 - 9:51 lixiang create.*/public class HoldLockDemo {private static Object[] lock = new Object[10];priv