ThreadLocal

ThreadLocal

map 和thread 关联 map里面的键是threadLocal 对象, value 是值

Thread ThreadLocalMap ThreaLocal 关系

  1. Thread内含ThreadLocalMap, 放入(this, value)
    ![](_assets/

用处

Spring的事务管理,用ThreadLocal存储Connection,从而各个DAO可以获取同一Connection,可以进行事务回滚,提交等操作。

  1. 先从对应线程上获取对应的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中的,不清除越来越对炸了

posted @ 2020-07-20 20:48  jojoworld  阅读(148)  评论(0编辑  收藏  举报