ThreadLocal
-
什么是ThreadLocal?
ThreadLocal 是线程本地变量类,在多线程并行执行过程中,将变量存储在ThreadLocal中,每个线程中都有独立的变量,因此不会出现线程安全问题。 -
应用举例
解决线程安全问题:例如每个线程都绑定一个数据库连接,避免多个线程访问同一个数据库连接:SqlSession
跨函数参数传递:同一个线程,跨类,跨方法传递参数的时候可以使用ThreadLocal,每个线程绑定一个Token/Session -
关于ThreadLocal
1)一个线程只能有一个ThreadLocal吗?
首先我们看到Thread里面,有一个ThreadLocalMap,可以看到再java1.8之后,每个线程都有自己的ThreadLocalMap
而这个ThreadLocalMap 里面可以明显的看到是一个数组用于存储多个Entry
我们看ThreadLocal的源码可以发现最终是调用ThreadLocalMap里面的方法:
createMap方法:
ThreadLocalMap里面的set方法:
关于ThreadLocalMap的哈希探测可以参考此文
这篇文章写的非常的详细,更多的展示了源码的细节
- Entry 的 Key 为什么需要使用弱引用?如果是强引用会造成什么问题?
因为弱引用在GC回收时会被回收,如果使用强引用,我们某个方法里面创建了一个ThreadLocal,我们肯定使用了new关键字,这个时候是强引用,如果这个方法结束,对于这个方法的引用应该解除并且回收掉,如果我们Entry里面使用强引用就会造成内存泄漏,这个已经ThreadLocal已经用不到了,但是由于key是强引用导致始终无法被回收掉。这样的话有资源一直回收不掉,堆积后最终就会OOM内存溢出。
- 使用案例(持续补充)
1)传递共享参数
@Setter
public class DemoTask {
private ThreadLocal threadLocal;
public void execute() {
// 对threadLoca的变量进行操作,只要是同一个ThreadLocal 一定是相同的值
System.out.println(JSONUtil.toJsonStr(threadLocal.get()));
}
}
public class ThreadLocalDemo {
static ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal();
public void init() {
threadLocal.set(new HashMap<String,Object>(){{
put( "k1", 1);
put( "k2", "v");
}});
}
public void passParms() {
DemoTask demoTask = new DemoTask();
demoTask.setThreadLocal(threadLocal);
demoTask.execute();
System.out.println(JSONUtil.toJsonStr(threadLocal.get()));
}
public static void main(String[] args) {
ThreadLocalDemo threadDemo = new ThreadLocalDemo();
threadDemo.init();
threadDemo.passParms();
}
}