ThreadLocal线程隔离值为NULL(直接cv使用封装类)

ThreadLocal笔记

介绍:

ThreadLocal 并不是一个Thread,而是Thread的局部变量。
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

常用方法:

  • public void set(T value) 设置当前线程的线程局部变量的值
  • public T get() 返回当前线程所对应的线程局部变量的值
  • public void remove() 移除当前线程的线程局部变量
image-20221111212349365

封装 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();
    }

}

失效案例:

线程隔离导致ThreadLocal上下文失效为Null案例:

登录线程:

image-20250729180924473image-20250729181033261

修改密码线程:

image-20250729181114269

image-20250729181134897

线程隔离导致获取的上下文值为空null

解决方法:拦截器跟每个线程都一起为一个中的:

image-20250729181233596

根本原因:

  • 登录接口和修改密码接口是两个不同的HTTP请求,每个请求都由独立的线程处理。
  • BaseContext(ThreadLocal)存储的变量是线程隔离的,即每个线程拥有自己独立的副本。
  • 在登录请求的线程中设置empId,并不会影响到修改密码请求的线程。
解决方案:
  • 用户登录成功后,在拦截器(或过滤器)中统一设置ThreadLocal(BaseContext)才是正确的做法,因为每个请求都会经过拦截器,且拦截器在当前请求的线程中设置empId,后续的Controller和Service层都可以在同一个线程中获取到。
  • 而登录接口中设置的empId只对当前登录请求有效,对后续的修改密码请求无效。

因此,用户已经发现:在拦截器中设置BaseContext存储empId就能在修改密码请求中调用出来。所以需要调整代码,移除在登录接口中设置BaseContext的代码,只在拦截器中设置。

posted @ 2025-07-29 18:19  张大帅Java  阅读(28)  评论(0)    收藏  举报