ThreadLocal用法
# threadLocal作用
从Java官方文档中的描述:ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文。
我们可以得知 ThreadLocal 的作用是:提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的复杂度。
1、线程并发: 在多线程并发的场景下
2、传递数据: 我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量, 保存每个线程绑定的数据,在需要的地方可以直接获取, 避免参数直接传递带来的代码耦合问题
3、线程隔离: 每个线程的变量都是独立的,不会互相影响, 各线程之间的数据相互隔离却又具备并发性,避免同步方式带来的性能损失
# threadLocal用法
方法声明 | 描述 |
---|---|
private static ThreadLocal<类> holder = new ThreadLocal<>(); | 创建ThreadLocal对象 |
public void set( T value) | 设置当前线程绑定的局部变量 |
public T get() | 获取当前线程绑定的局部变量 |
public void remove() | 移除当前线程绑定的局部变量 |
/**
* 请求数据的临时容器
*
* @author fengshuonan
* @date 2018-05-04 11:33
*/
public class RequestDataHolder {
// 类似 private RequestData holder = new RequestData();
private static ThreadLocal<RequestData> holder = new ThreadLocal<>();
public static void put(RequestData s) {
if (holder.get() == null) {
holder.set(s);
}
}
public static RequestData get() {
return holder.get();
}
public static void remove() {
holder.remove();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# ThreadLocal与synchronized的区别
虽然ThreadLocal模式与synchronized关键字都用于处理多线程并发访问变量的问题, 不过两者处理问题的角度和思路不同。
synchronized | ThreadLocal | |
---|---|---|
原理 | 同步机制采用’以时间换空间’的方式, 只提供了一份变量,让不同的线程排队访问 | ThreadLocal采用’以空间换时间’的方式, 为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰 |
侧重点 | 多个线程之间访问资源的同步 | 多线程中让每个线程之间的数据相互隔离 |
# 用法1:service中拿到请求参数
原理:先将请求的数据封装到
RequestData
当中,然后交由RequestDataHolder
管理,ThreadLocal将RequestData其与当前线程绑定,就可以在service中拿到数据了
因为请求都会经过controller,因此采用aop
就可以解决, requestDataConverter和FastjsonConverter也都可以存RequestData
/**
* 对控制器调用过程中,提供一种RequestData便捷调用的aop
* <p>
* 废弃掉了,因为requestDataConverter和FastjsonConverter都可以存RequestData
*
* @author fengshuonan
* @date 2016年11月13日 下午10:15:42
*/
@Aspect
@Order(REQUEST_DATA_AOP_SORT)
public class RequestDataAop {
@Pointcut("execution(* *..controller.*.*(..))")
public void cutService() {
}
@Around("cutService()")
public Object sessionKit(ProceedingJoinPoint point) throws Throwable {
Object result;
try {
result = point.proceed();
} finally {
//清空 RequestDataHolder
RequestDataHolder.remove();
}
return result;
}
}
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
/**
* 快捷获取HttpServletRequest,HttpServletResponse 的工具类
*
* @author stylefeng
* @Date 2018/1/4 21:24
*/
public class HttpContext {
/**
* 获取请求的ip地址
*
* @author fengshuonan
* @Date 2018/7/23 下午3:44
*/
public static String getIp() {
HttpServletRequest request = HttpContext.getRequest();
if (request == null) {
return "127.0.0.1";
} else {
return request.getRemoteHost();
}
}
/**
* 获取当前请求的Request对象
*
* @author fengshuonan
* @Date 2018/7/23 下午3:44
*/
public static HttpServletRequest getRequest() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
return null;
} else {
return requestAttributes.getRequest();
}
}
/**
* 获取当前请求的Response对象
*
* @author fengshuonan
* @Date 2018/7/23 下午3:44
*/
public static HttpServletResponse getResponse() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
return null;
} else {
return requestAttributes.getResponse();
}
}
/**
* 获取所有请求的值
*
* @author fengshuonan
* @Date 2018/7/23 下午3:44
*/
public static Map<String, String> getRequestParameters() {
HashMap<String, String> values = new HashMap<>();
HttpServletRequest request = HttpContext.getRequest();
if (request == null) {
return values;
}
Enumeration enums = request.getParameterNames();
while (enums.hasMoreElements()) {
String paramName = (String) enums.nextElement();
String paramValue = request.getParameter(paramName);
values.put(paramName, paramValue);
}
return values;
}
}
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# 用法二:缓存
缓存一次调用中,高频调用的属性,如用户id, 数据库连接等。
# 用法三:结合aop使用
ThreadLocal使用不当,易造成内存泄露,要及时关闭。
参考源码: RequestContextHolder
参考文章:
由浅入深,全面解析ThreadLocal_LeslieGuGu的博客-CSDN博客 (opens new window)
面试中跌倒的ThreadLocal避坑指南2:ThreadLocal用法大揭秘_哔哩哔哩_bilibili (opens new window)
黑马程序员Java基础教程由浅入深全面解析threadlocal_哔哩哔哩_bilibili (opens new window)