ThreadLocal笔记
介绍:
ThreadLocal 并不是一个Thread,而是Thread的局部变量。
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
常用方法:
- public void set(T value) 设置当前线程的线程局部变量的值
- public T get() 返回当前线程所对应的线程局部变量的值
- public void remove() 移除当前线程的线程局部变量

封装 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案例:
登录线程:
修改密码线程:
线程隔离导致获取的上下文值为空null
解决方法:拦截器跟每个线程都一起为一个中的:
根本原因:
- 登录接口和修改密码接口是两个不同的HTTP请求,每个请求都由独立的线程处理。
- BaseContext(ThreadLocal)存储的变量是线程隔离的,即每个线程拥有自己独立的副本。
- 在登录请求的线程中设置empId,并不会影响到修改密码请求的线程。
解决方案:
- 用户登录成功后,在拦截器(或过滤器)中统一设置ThreadLocal(BaseContext)才是正确的做法,因为每个请求都会经过拦截器,且拦截器在当前请求的线程中设置empId,后续的Controller和Service层都可以在同一个线程中获取到。
- 而登录接口中设置的empId只对当前登录请求有效,对后续的修改密码请求无效。
因此,用户已经发现:在拦截器中设置BaseContext存储empId就能在修改密码请求中调用出来。所以需要调整代码,移除在登录接口中设置BaseContext的代码,只在拦截器中设置。