ThreadLocal应用

ThreadLocal是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。在应用中,通常用来保存一些需要多次调用的数据,减少用户请求和代码量,而且数据对于其他线程是隔离的。

简介

从名字我们就可以看到ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

从实际使用的角度来看,可以有以下用途:

  • 在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。
  • 线程间数据隔离。
  • 进行事务操作,用于存储线程事务信息。
  • 数据库连接,Session会话管理。

实际应用

以保存用户信息为例,ThreadLocal可以把用户信息保存在线程中,用户发来的每一次请求启动的线程到保存了用户信息,当请求结束,我们会把保存的用户信息清除掉,这样就方便我们在开发中获取用户登录信息。

实现方式

  • 创建一个ThreadLocal类,创建一个ThreadLocal对象,设置ThreadLocal的set,remove,get方法;
  • 定义一个登录的拦截器类,实现HandlerInterceptor ,重写 preHandle() 和afterCompletion()方法 ,preHandle ()方法把登录信息写入ThreadLocal,afterCompletion()方法清除登录信息;
  • 设置一些配置信息,创建一个类实现 WebMvcConfigurer ,重写addInterceptors()方法,创建一个登录拦截器类的对象,给他添加到配置中。
ThreadLocal类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ThreadLocalUser {

private ThreadLocalUser(){
}

private static final ThreadLocal<UserInfo> userLocal = new ThreadLocal<>();

/**
* 清除用户信息
*/
public static void remove() {
userLocal.remove();
}

/**
* 存储用户信息
*/
public static void set(UserInfo userInfo) {
userLocal.set(userInfo);
}

/**
* 获取当前用户信息
*/
public static UserInfo get() {
return userLocal.get();
}
}
登录拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
public class LoginInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
UserInfo userInfo = getUserInfo(request);
ThreadLocalUser.set(userInfo);
return true;
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
ThreadLocalUser.remove();
}
}
WebConfig
1
2
3
4
5
6
7
8
9
10
@Configuration
public class WebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
// 所有请求都拦截
.addPathPatterns("/**");
}
}