ThreadLocal
ThreadLocal
map 和thread 关联 map里面的键是threadLocal 对象, value 是值
Thread ThreadLocalMap ThreaLocal 关系
- Thread内含ThreadLocalMap, 放入(this, value)
![](_assets/
用处
Spring的事务管理,用ThreadLocal存储Connection,从而各个DAO可以获取同一Connection,可以进行事务回滚,提交等操作。
- 先从对应线程上获取对应的ThreadLocalMap 从ThreadLocalMap 中根据ThreadLocal 键值 设置值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
// 1个线程对应一个 ThreadLocalMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
// ThreadLocalMap
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
强引用、软引用、弱引用和虚引用
tab[i] = new Entry(key, value);
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
WeakReference对应用的对象userInfoLocal是弱引用,不会影响到userInfoLocal的GC行为。如果是强引用的话,在线程运行过程中,我们不再使用userInfoLocal了,将userInfoLocal置为null,但userInfoLocal在线程的ThreadLocalMap里还有引用,导致其无法被GC回收(当然,可以等到线程运行结束后,整个Map都会被回收,但很多线程要运行很久,如果等到线程结束,便会一直占着内存空间)。而Entry声明为WeakReference,userInfoLocal置为null后,线程的threadLocalMap就不算强引用了,userInfoLocal就可以被GC回收了。map的后续操作中,也会逐渐把对应的"stale entry"清理出去,避免内存泄漏。
实际上只要ThreadLocal被定义成static的,那个WeakReference就是没有用的。因为static字段就是强引用,并且只要class load之后就永远可达
那个WeakReference可能有用的时候是ThreadLocal不被定义为static的,它被作为参数在方法之间以及各线程之间传递。等到所有线程都不再能访问到它了,GC会把它回收。但是此时map里的那个entry还在,它包裹的对象是null了,那个value值也还在。它会在下一次expungeStaleEntry时被从map中清理掉。
ThreadLocalMap内部Entry中key使用的是对ThreadLocal对象的弱引用,这为避免内存泄露是一个进步,因为如果是强引用,那么即使其他地方没有对ThreadLocal对象的引用,ThreadLocalMap中的ThreadLocal对象还是不会被回收,而如果是弱引用则这时候ThreadLocal引用是会被回收掉的,虽然对于的value还是不能被回收,这时候ThreadLocalMap里面就会存在key为null但是value不为null的entry项,虽然ThreadLocalMap提供了set,get,remove方法在一些时机下会对这些Entry项进行清理,但是这是不及时的,也不是每次都会执行的,所以一些情况下还是会发生内存泄露,所以在使用完毕后即使调用remove方法才是解决内存泄露的王道
为什么使用完要清除:
使用的是线程池,创建的ThradeLocal 是作为Key 放在线程绑定的ThradLocalMap中的,不清除越来越对炸了