ThreadLocal源码分析

225 阅读3分钟

java.lang.ThreadLocal

ThreadLocalMap


static class ThreadLocalMap {

 /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
        private Entry[] table; 


 /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;


  /**
         * Construct a new map initially containing (firstKey, firstValue).
         * ThreadLocalMaps are constructed lazily, so we only create
         * one when we have at least one entry to put in it.
         */
        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {


            table = new Entry[INITIAL_CAPACITY]; // 数组长度16

            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); // 确定index, 确定数组中的位置


            table[i] = new Entry(firstKey, firstValue);

            size = 1;

            setThreshold(INITIAL_CAPACITY);// 当数组负载达到了,就得触发扩容。

        }



Entry


// 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.
//当key==null, 则直接删除key对象; 这就是为啥要继承WeakReference的原因了。
 static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k); // key作为weakReference对象的referent字段, 当key代表的threadLocal对象删除了强引用, 则在下一次gc回收的时候,就会回收掉referent, 即回收掉threadlocal对象。

                   //而entry对象作为reference对象本身, 当删除掉强引用后,就会被gc回收。

                value = v;
            }
        }

ThreadLocal


/**
     * The next hash code to be given out. Updated atomically. Starts at
     * zero.
     */
    private static AtomicInteger nextHashCode =
        new AtomicInteger();

    /**
     * The difference between successively generated hash codes - turns
     * implicit sequential thread-local IDs into near-optimally spread
     * multiplicative hash values for power-of-two-sized tables.
     */
// 0110 0001 1100 1000 1000 0110 0100 0111
    private static final int HASH_INCREMENT = 0x61c88647;

    /**
     * Returns the next hash code.
     */
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

hashCode

如何避免或者减少碰撞呢?

如果碰撞了怎么办?

set


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

            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)]) { //  旧的entry替换新值

                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); //  插入新entry 

            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold) // 数组扩容
                rehash();
        }

Thread

    ThreadLocal.ThreadLocalMap threadLocals = null;

  • ThreadLocal.createMap

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue); // key=threadLocal 
    }

  • ThreadLocal.get
 public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t); //取出caller线程的threadLocals字段

        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this); // 根据caller ThreadLocal 对象作为key, 查找value值

            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

ThreadLocal、ThreadLocalMap、 Thread三者之间的关系

  • Thread维护一个ThreadLocalMap类型的字段
    ThreadLocal.ThreadLocalMap threadLocals = null;

  • ThreadLocalMap以Entry类型作为节点

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

            Entry(ThreadLocal<?> k, Object v) {
                super(k); // threadLocal对象
                value = v; // 值
            }
        }


单个Thread实例可以保存多个threadlocal实例及value

  • ThreadLocal是工具、标识符 ThreadLocal.get 根据caller线程和 ThreadLocal对象找到value。

一个ThreadLocal实例作为多个Entry实例的key, 这多个Entry实例分别保存在多个Thread的threadLocals字段中。

也就是说线程内部的value数据, 线程实例自己保存在threadLocals字段中。

threadlocal对象,仅仅作为一个标识符和获取工具。

 public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t); //取出caller线程的threadLocals字段

        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this); // 根据caller ThreadLocal 对象作为key, 查找value值

            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }