参考链接:
其他先不看 先学习 threadlocal
ThreadLocal
ThreadLocal 不同于普通的局部变量和全局变量,它可以理解为全局变量,但在线程维度属于局部变量。也就是说,ThreadLocal在多线程中为每一个线程开一个变量副本,不同线程的修改不会相互影响,也就从解决了某些场景下的并发问题。
应用场景
下面给出具体的使用案例:
数据库连接
https://www.cnblogs.com/-beyond/p/13111015.html 这里举了个用于数据库获取的例子:
假设要实现一个事务,包含a和b步骤。没用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
29
30
|
public class DBUtil {
// 返回数据库连接
public static Connection getConnectionFromPool() throws SQLException {
return dataSource.getConnection();
}
}
public class UserService {
try{
// 获取数据库连接
// 关于此连接的自动提交
// 步骤a a()
// 步骤b b()
} catch (Exception e) {
// 回滚此连接
}
public class UserDao {
// 定义方法a(),b()
a() {
// 获取数据库连接
// a的动作
}
b() {
// 获取数据库连接
// b的动作
}
}
}
|
会产生一个问题:没法保证UserService和UserDao方法里获取的数据库连接是同一个,这样就保证步骤a和b的数据库连接是被设置为notAutiCommit,因此回滚可能失败。
一个解决方案是可以通过传参将此连接参数传递到方法中,这样就能精确使用此连接参数。但是这种做法很不优雅,维护成本也高。
如果使用ThreadLocal,一切就简单许多:
1
2
3
4
5
6
7
8
9
10
11
|
// 只需要在DBUtil中将获取的连接设置为ThreadLocal,其他两个类不用改
public class DBUtil {
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
// 返回数据库连接
public static Connection getConnectionFromPool() throws SQLException {
if (threadlocal.get() == null) {
threadLocal.set(datasource.getConnection);
}
return threadLocal.get();
}
}
|
ThreadLocal的副作用
内存泄露