什么是 ThreadLocal?

什么是 ThreadLocal?

ThreadLocal 是 Java 提供的一个类,它用于创建线程局部变量。每个使用 ThreadLocal 创建的变量都与当前线程关联,意味着每个线程都有自己的独立变量副本。这种机制允许在多线程环境下避免共享数据时的竞争条件。
在这里插入图片描述

主要特性

1、线程隔离:每个线程都有自己的 ThreadLocal 变量副本,互不干扰。即使多个线程访问同一个 ThreadLocal 实例,它们获取到的值都是不同的。

2、简化编程模型:开发者可以直接使用 ThreadLocal 来存储线程相关的数据,而不需要进行显式的同步。

3、内存管理:在使用完 ThreadLocal 后,可以通过 remove() 方法显式地清理,从而防止潜在的内存泄漏。

使用场景

1、用户会话管理:
在 Web 应用中,可以将用户信息(如用户 ID、权限等)存储在 ThreadLocal 中,以便在同一请求的多个处理方法中共享。
例:如果想在ServiceImpl获取登录者的id;在拦截器中获取token存放的id值,再将id存放进ThreadLocal中set(id),最后在ServiceImpl中通过ThreadLocal的get()方法获取id。
可以在整个项目共享一个变量

2、数据库连接:
为每个线程分配一个数据库连接,避免连接竞争和共享问题。通过 ThreadLocal 可以确保每个线程使用自己的连接。

3、事务管理:
在涉及分布式事务的场景中,每个线程可以持有自己的事务上下文,确保事务操作的一致性。

4、日志上下文:
在多线程日志框架中,可以使用 ThreadLocal 存储每个线程的日志上下文,如请求 ID,方便在日志中追踪请求的流转。

基本用法

public class ThreadLocalExample {
    // 声明一个 ThreadLocal<Long> 变量,用于存储每个线程独立的 Long 类型数据
    public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
        // 创建一个 Runnable 任务,定义线程要执行的操作
        Runnable task = () -> {
            // 设置当前线程的 ThreadLocal 变量为当前线程的 ID
            threadLocal.set(Thread.currentThread().getId());
            
            // 获取并打印当前线程的 ThreadLocal 变量的值
            System.out.println("Thread ID: " + threadLocal.get());
        };

        // 创建两个线程,执行相同的任务
        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        // 启动线程
        thread1.start();
        thread2.start();
    }
}

1、ThreadLocal threadLocal:声明了一个 ThreadLocal 变量 threadLocal。这个变量用于存储每个线程的局部数据,即使多个线程同时访问,它们也会各自拥有自己的值。

2、Runnable task:使用 Lambda 表达式创建了一个 Runnable 任务,定义了线程执行时要执行的操作。

3、threadLocal.set(Thread.currentThread().getId()):调用 set() 方法,将当前线程的 ID 存储到 threadLocal 中。这样,每个线程在运行时都会将自己的 ID 保存到自己的 ThreadLocal 副本中。

4、threadLocal.get():调用 get() 方法,从 threadLocal 中获取当前线程的值,并打印出来。由于每个线程都有自己的副本,因此这里得到的值对每个线程是独立的。

5、Thread thread1 和 Thread thread2:创建了两个线程,分别执行相同的任务。这展示了 ThreadLocal 的特性,即使在多线程环境中,每个线程都能独立存取自己的状态。

6、thread1.start() 和 thread2.start():启动两个线程,使它们开始执行任务。

重要方法

get():获取当前线程的 ThreadLocal 变量值。如果该线程没有设置该值,返回初始值。

set(T value):设置当前线程的 ThreadLocal 变量值。如果该线程之前没有设置过,会将其设置为提供的值。

remove():移除当前线程的 ThreadLocal 变量,释放内存。

withInitial(Supplier<? extends T> supplier):创建一个新的 ThreadLocal 实例,并为其设置初始值。

内部原理

实现机制:ThreadLocal 内部使用了一个 ThreadLocalMap,这个映射表是每个线程私有的。ThreadLocalMap 的键是 ThreadLocal 实例,值则是对应的线程局部变量。

垃圾回收:因为 ThreadLocal 持有对 ThreadLocalMap 的引用,如果线程没有结束,可能导致内存泄漏。因此应尽量调用 remove() 方法以避免不必要的内存占用。

注意事项

内存泄漏:
如果 ThreadLocal 的值引用了外部对象,并且线程未结束,这可能导致外部对象无法被垃圾回收,从而引发内存泄漏。因此,使用 remove() 方法清理。

性能开销:
ThreadLocal 的使用会带来一定的性能开销,尤其是在高并发环境下,因为每个线程都有独立的副本。

调试复杂性:
由于 ThreadLocal 变量的值是线程专有的,调试时可能会增加困难,特别是在跨线程操作和错误追踪时。

ThreadLocal工具类实现

public class BaseContext {

    public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    public static Long getCurrentId() {
        return threadLocal.get();
    }

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

}

苍穹外卖p20

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

╰つ゛木槿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值