ThreadLocal的理解和使用

理解

ThreadLocal是一种用于在多线程环境中存储线程局部变量的机制,它为每个线程都提供了独立的变量副本,从而避免了线程之间的竞争条件,事实上ThreadLocal的工作原理是在每个线程中创建一个独立的变量副本,并且每个线程只能访问自己的副本。ThreadLocal一个最广泛的使用场景就是将信息保存,从而方便后续方法直接从线程中获取。

ThreadLocal核心方法
方法声明 描述
public void set(T value) 设置当前线程绑定的局部变量
public T get() 获取当前线程绑定的局部变量
Public void remove() 移除当前线程绑定的局部变量
TheadLocal使用
public class LoginUserContextHolder {
    
    /**
     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
     * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
     */
    private static final ThreadLocal threadLocal = new ThreadLocal<>();

    /**
     * 设置变量
     */
    public static void set(LoginUser user) {
        threadLocal.set(user);
    }

    /**
     * 获得变量
     */
    public static LoginUser get() {
        return threadLocal.get();
    }

    /**
     * 清理当前变量
     */
    public static void remove() {
        threadLocal.remove();
    }
}

实际例子: 前端使用token令牌调用后端接口,后端在Filter(过滤器)中拦截token令牌,然后判断token是否有效可用,从而可获取登录时存储在Redis中的用户信息,然后通过上述方法将登录用户信息放入到ThreadLocal中,那么在执行到接口层就可通过ThreadLocal获取到当前登录用户信息。

注意点

使用完后要进行手动释放,要不然会造成内存泄漏,也可能导致意外的数据污染或不一致性。

内存泄漏:上述threadLocal对象,若没有手动删除当前线程的用户信息,每次请求执行接口时都会创建一个不同的线程,都会将用户信息放到threadLocal对象中,而threadLocal的生命周期相当于应用系统的生命周期,GC无法回收,这样就会导致执行接口次数越多,内存泄漏得越多。

数据污染或不一致性:上述threadLocal对象,若没有手动删除当前线程的用户信息,可能会导致不同的token令牌请求(用户不同)会得到同一个用户信息。主要原因是使用线程池,线程池是拥有核心线程数和最大线程数的,核心线程会一直存在那里不会销毁,核心线程外的最大线程是有一定的存活时间,那么就有可能当前接口的线程就存活在线程池中,从而得到错误的用户信息。

你可能感兴趣的:(java,ThreadLocal,线程)