ThreadLocal源码学习

108 阅读1分钟

为每个线程保存一个变量副本 先看java.lang.ThreadLocal#set方法

    public void set(T value) {
        Thread t = Thread.currentThread(); //获取当前运行的线程
        ThreadLocalMap map = getMap(t); 
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue); //当前线程的java.lang.Thread#threadLocals被初始化,this时当前threadLoacl对象
    }

非常简单,就是获取ThreadLocalMap对象,然后去set,接下来看看java.lang.ThreadLocal.ThreadLocalMap#set

 private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table; //弱引用,垃圾回收时会被释放
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);//hash

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value); //存到tab中
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

可以看到值真正存到java.lang.ThreadLocal.ThreadLocalMap#table中,而table是一个java.lang.ThreadLocal.ThreadLocalMap.Entry对象

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

可以看到Entry是持有ThreadLocal的一个弱引用,这意味着当垃圾回收时,Entry的k没有其他强引用的时候就会被回收,那么就无法根据获取到v,而v又没有被释放,就会造成内存泄漏