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

简介: 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;
        }
 
        @Override
        public 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 变量可能会增加线程间切换的开销,需要权衡使用场景和性能影响。


相关文章
|
JavaScript 安全 前端开发
TypeScript中的枚举类型有哪些应用场景
【8月更文挑战第4天】TypeScript中的枚举类型有哪些应用场景
308 5
|
人工智能 自动驾驶 机器人
智能时代的桥梁:人工智能与人类协作的未来
随着人工智能技术的不断进步,其在各行各业的应用已经变得越来越广泛。本文将探讨AI技术如何成为连接人与人、人与机器、以及机器与机器的桥梁,促进更高效的协作模式,并分析这种协作对未来社会的影响。我们将通过具体实例来展示人工智能在提升工作效率、解决复杂问题以及创新服务方面的潜力,同时也会触及到这一过程中可能遇到的挑战和伦理问题。
|
存储 Java 程序员
汇编语言教程及实例
汇编语言教程及实例
|
存储 前端开发 安全
如何处理大文件上传
【4月更文挑战第20天】
1332 9
|
XML 存储 缓存
Spring 中 Bean 的作用域以及生命周期
Spring 中 Bean 的作用域以及生命周期
311 0
|
SQL Linux 应用服务中间件
linux(七)linux的服务管理(1)
(2):服务命令 立即启动一个服务 sql 复制代码 sudo systemctl start nginx 立即停止一个服务 arduino 复制代码 sudo systemctl stop nginx 重启一个服务 复制代码 sudo systemctl restart nginx 设置开机自启动 bash 复制代码 systemctl enable nginx 停止开机自启动 bash 复制代码 systemctl disable nginx 杀死一个服务的所有子进程 bash 重新加载一个服务的配置文件
124 0
linux(七)linux的服务管理(1)
KNN中KD树的查询操作
KNN中KD树的查询操作
185 0
|
存储 算法 搜索推荐
【数据结构】什么是拓扑排序—关于图的拓扑排序
【数据结构】什么是拓扑排序—关于图的拓扑排序
1087 0
【数据结构】什么是拓扑排序—关于图的拓扑排序
|
存储 Linux 文件存储
Linux驱动入门(6.1)LED驱动---设备树
Linux驱动入门(6.1)LED驱动---设备树
634 0
|
机器学习/深度学习 人工智能 自然语言处理
RISC-V生态全景解析(九):平头哥剑池CDK介绍
编辑语: 芯片开放社区(OCC)面向开发者推出RISC-V系列内容,通过多角度、全方位解读RISC-V,系统性梳理总结相关理论知识,构建RISC-V知识图谱,促进开发者对RISC-V生态全貌的了解。
1397 0
RISC-V生态全景解析(九):平头哥剑池CDK介绍