You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {//当map已存在
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();//初始化值
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
一、用法
把要线程隔离的数据放进ThreadLocal
线程获取相关数据的时候只要
想修改、赋值只要
二 、使用场景
如上面说到的,ThreadLocal是用于线程间的数据隔离,ThreadLocal为每个线程都提供了变量的副本。
举例1:联想一下服务器(例如tomcat)处理请求的时候,会从线程池中取一条出来进行处理请求,如果想把每个请求的用户信息保存到一个静态变量里以便在处理请求过程中随时获取到用户信息。这时候可以建一个拦截器,请求到来时,把用户信息存到一个静态ThreadLocal变量中,那么在请求处理过程中可以随时从静态ThreadLocal变量获取用户信息。
举例2:Spring的事务实现也借助了ThreadLocal类。Spring会从数据库连接池中获得一个connection,然会把connection放进ThreadLocal中,也就和线程绑定了,事务需要提交或者回滚,只要从ThreadLocal中拿到connection进行操作。
三、原理分析
1、get()方法
来看下ThreadLocal的内部类ThreadLocalMap源码,留个大致印象
回顾下get()方法中的代码
map为null或e为null就会走到setInitialValue,如果我们是第一次get()方法,那map会是空的,所以接下来先看setInitialValue()方法
map.set(this, value)这句代码在上面的ThreadLocalMap源码中可以看到大致流程,下面看看createMap()做了什么事
在回顾下get()方法中的代码
现在map不会为空了,再次调用get方法就会调用map的getEntry方法(上面的ThreadLocalMap源码中可以看到大致流程),拿到相应的Entry,然后就可以拿到相应的值返回出去
2、set方法
分析完get()方法,那么set()方法就自然而然的明白了,就不再赘述
总结
原理
ThreadLocal的实现原理是,在每个线程中维护一个Map,键是ThreadLocal类型,值是Object类型。当想获取ThreadLocal的值时,就从当前线程中拿出Map,然后在把ThreadLocal本身作为键从Map中拿出值返回。
优缺点
**优点:**提供线程内的局部变量。每个线程都自己管理自己的局部变量,互不影响
**缺点:**内存泄漏问题。可以看到ThreadLocalMap中的Entry是继承WeakReference的,其中ThreadLocal是以弱引用形式存在Entry中,如果ThreadLocal在外部没有被强引用,那么垃圾回收的时候就会被回收掉,又因为Entry中的value是强引用,就会出现内存泄漏。虽然ThreadLocal源码中的会对这种情况进行了处理,但还是建议不需要用TreadLocal的时候,手动调remove方法。
The text was updated successfully, but these errors were encountered: