ThreadLocalMap

174 阅读2分钟

ThreadLocalMap是个table数组, 每个table存储<key, value>(ThreadLocal<>, value).每个线程都有一个ThreadLocalMap, 同一个ThreadLocal对象会在每个线程都有数据, 每个线程会存储多个ThreadLocal对象.

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

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
	//2的幂
	private static final int INITIAL_CAPACITY = 16;
    // table数组存储数据, hash得到数组下标
    private Entry[] table;
    // hash冲突,往后偏移1个位置存储数据
    private static int nextIndex(int i, int len) {
            return ((i + 1 < len) ? i + 1 : 0);
    }
    private static int prevIndex(int i, int len) {
            return ((i - 1 >= 0) ? i - 1 : len - 1);
    }
    // 2/3扩容
    private void setThreshold(int len) {
            threshold = len * 2 / 3;
    }

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

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
				// 原来数组中已经存在该key键值对, 更新value值
                if (k == key) {
                    e.value = value;
                    return;
                }
				// 如果key为null, 从该位置开始清理key为null的数据, 并重新hash存储后面的数据
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            // 数组中没有找到, 新建Entry
            tab[i] = new Entry(key, value);
            int sz = ++size;
            // 清理一些槽位null数据, 数据数量达到阀值, 重hash扩容
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
		private Entry getEntry(ThreadLocal<?> key) {
        	// hashcode mod 数组长度得到下标
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            // 获取匹配key数据成功,返回数据
            if (e != null && e.get() == key)
                return e;
            else
            	// 命中失败,往后面nextIndex查找
                return getEntryAfterMiss(key, i, e);
        }
		private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
            Entry[] tab = table;
            int len = tab.length;

            while (e != null) {
                ThreadLocal<?> k = e.get();
                // 往后查找数据匹配,返回
                if (k == key)
                    return e;
                // 往后查找发现key null的数据, 存在破坏失效数据,需要清除并且重新hash后面的数据
                if (k == null)
                    expungeStaleEntry(i);
                else
                // 移动指针往后查找
                    i = nextIndex(i, len);
                e = tab[i];
            }
            return null;
        }
	// index i开始存在破坏失效数据,需要清除并且重新hash后面的数据
	private int expungeStaleEntry(int staleSlot) {
            Entry[] tab = table;
            int len = tab.length;

            // expunge entry at staleSlot
            // 将index staleSlot数据置null
            tab[staleSlot].value = null;
            tab[staleSlot] = null;
            // size - 1
            size--;

            // Rehash until we encounter null
            Entry e;
            int i;
            // 从staleSlot开始往后index,遍历数据key是否为null
            for (i = nextIndex(staleSlot, len);
                 (e = tab[i]) != null;
                 i = nextIndex(i, len)) {
                ThreadLocal<?> k = e.get();
                // key值为null, 需要置null回收
                if (k == null) {
                    e.value = null;
                    tab[i] = null;
                    size--;
                } else {
                	// key值不为null, 数据有效, 重新计算索引值
                    int h = k.threadLocalHashCode & (len - 1);
                    // 新值不是原来的了
                    if (h != i) {
                    	// 将原来坑位置null
                        tab[i] = null;

                        // Unlike Knuth 6.4 Algorithm R, we must scan until
                        // null because multiple entries could have been stale.
                        // 若hash冲突, 该位置已经存储别的数据
                        while (tab[h] != null)
                        	// 往后查找合适位置
                            h = nextIndex(h, len);
                        // 得到合适位置, 存放数据    
                        tab[h] = e;
                    }
                }
            }
            return i;
        }
	// 达到阀值, 扩容2倍, 所有数据重新计算索引
	private void resize() {
            Entry[] oldTab = table;
            int oldLen = oldTab.length;
            int newLen = oldLen * 2;
            Entry[] newTab = new Entry[newLen];
            int count = 0;

            for (int j = 0; j < oldLen; ++j) {
                Entry e = oldTab[j];
                if (e != null) {
                    ThreadLocal<?> k = e.get();
                    if (k == null) {
                        e.value = null; // Help the GC
                    } else {
                        int h = k.threadLocalHashCode & (newLen - 1);
                        while (newTab[h] != null)
                            h = nextIndex(h, newLen);
                        newTab[h] = e;
                        count++;
                    }
                }
            }

            setThreshold(newLen);
            size = count;
            table = newTab;
        }