ThreadLocal

ThreadLocal变量又可以称为线程变量,ThreadLocal内部实现为每一个线程保存了一份副本变量。
每一个线程都有一个map对象,map对象中存放了ThreadLocal对象的副本变量。
threadLocal.png

set方法详解

public void set(T value) {
        //拿到当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

getMap方法返回线程的threadLocals变量

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals变量;
    }

查看Thread的182行有一个ThreadLocalMap threadLocals变量,188有一个InheritableThreadLocal变量。

class Thread implements Runnable {
    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

    /*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

上面可以看到每一个线程中都有ThreadLocalMap对象,再看看是ThreadLocal是怎么赋值的。在set的时候判断map==null,走创建map流程。

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);
    }

查看ThreadLocalMap(this, firstValue)这个构造方法。

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);
        }

看下以下的一个结构图,ThreadLocalMap他自己又有一个
是ThreadLocal的一个内部类,而ThreadLocalMap他自己又有一个Entry内部类。
image.png~~~~

看Entry类,继承了WeakReference,是一个弱引用。

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

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

再继续看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);
        }
          /** The value associated with this ThreadLocal. */
            Object value;

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

        private Entry[] table;

内部有一个Entry[] table,key就是变量自己、value就是变量的副本。

get方法

每一个线程有一个map,这个map存放了threadLocal对象的副本变量。查看get方法是如何获取变量的。
//获取当前线程的map,从map对象里获取到entry对象,并将其中的value返回。

public T get() {
        //当前线程
        Thread t = Thread.currentThread();
        //拿到当前线程的map(ThreadLocalMap)对象。
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            //获取entry对象,this是threadlocal对象
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                //获取value并返回
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

remove方法

再使用完threadlocal之后记得主动的remove变量。
获取map对象,调用内部的remove方法。

 public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

获取当前的table,移除当前key对应的entry。

private void remove(ThreadLocal<?> key) {
            Entry[] tab = table;~~~~
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                if (e.get() == key) {
                    e.clear();
                    expungeStaleEntry(i);
                    return;
                }
            }
        }

李沁春
17 声望1 粉丝

喜欢运动,骑行、打羽毛球、打乒乓球等。也喜欢打桌游,玩狼人杀、剧本杀等烧脑游戏。