什么是ThrealLocal


ThreadLocal,即线程局部存储,是一种在多线程编程中用于隔离线程数据的技术

定义与概念

ThreadLocal 为每个使用该变量的线程都提供一个独立的变量副本,每个线程可以独立地修改自己的副本,而不会影响其他线程的副本。这样可以确保在多线程环境下,各个线程之间的数据相互隔离,避免了数据冲突和并发安全问题。

工作原理

  • 内部存储结构:ThreadLocal 内部通常使用一个 Map 来存储数据,其中以当前线程作为键,以线程对应的变量副本作为值。这样,每个线程都可以通过自己的线程标识来访问和操作属于自己的变量副本。

  • 数据访问与隔离:当一个线程访问 ThreadLocal 变量时,它实际上是在访问自己线程对应的变量副本。每个线程都有自己独立的存储空间,所以不同线程之间对 ThreadLocal 变量的操作不会相互干扰。

封装ThreadLocal


其实ThreadLocal的几个方法非常简单,类似Map:

  • get() :获取当前线程的数据

  • set() :设置当前线程的数据

  • clear() :清除当前线程的数据

那既然ThreadLocal这么简单,为什么我们需要自己封装呢?

原因一:ThreaLocal的数据是泛型的,如果我们每次都手动指定数据类型比较麻烦

原因二:可以在set或get或clear操作时,进行一些处理(如数据校验、登录校验登)

示例代码

public class UserContext {
    // 创建一个ThreadLocal存储线程用户
    static ThreadLocal<User> threadLocal = new ThreadLocal<>();

    /**
     * 获取当前线程的用户
     *
     * @return 返回用户
     */
    public static User getUser() {
        return threadLocal.get();
    }

    /**
     * 设置当前线程是用户
     *
     * @param user 用户
     */
    public static void setUser(User user) {
        threadLocal.set(user);
    }

    /**
     * 清除当前线程用户
     */
    public static void clearUser() {
        threadLocal.remove();
    }

}

使用示例:

void testUserContext() {
    for (int i = 0; i < 5; i++) {
        new Thread(() -> {
            User user = new User();
            user.setId((int) Thread.currentThread().getId());
            UserContext.setUser(user);
            log.info("当前线程用户为: {}", UserContext.getUser());
            UserContext.clearUser();
        }).start();
    }
}