ThreadLocalMap是保存ThreadLocal的,每一个ThreadLocal类似HashMap的一个key-value映射
采用hash+数组的方式存储,hash冲突后就放入下一个(开放寻址法,线性探测再散列)
但ThreadLocalMap的entry不同于hashMap的entry,ThreadLocalMap的entry是WeakReference类型,只保存了value.把ThreadLocal作为WeakReference的reference
1.首先看一下Entry
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
2.成员变量
/** * The initial capacity -- MUST be a power of two. */ private static final int INITIAL_CAPACITY = 16;//初始容量 /** * The table, resized as necessary. * table.length MUST always be a power of two. */ private Entry[] table; /** * The number of entries in the table. */ private int size = 0; /** * The next size value at which to resize. */ private int threshold; // Default to 0//扩容阀值
3.构造函数
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);//设置阀值 }
4.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);//找到槽位 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);//写入槽位 int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold)//超过阀值,扩容 rehash(); }
5.resize方法
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; }
6.get方法
private Entry getEntry(ThreadLocal<?> key) { int i = key.threadLocalHashCode & (table.length - 1);//找到槽位 Entry e = table[i]; if (e != null && e.get() == key)//如果槽位key与要找的相同,返回 return e; else 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; if (k == null) expungeStaleEntry(i);//清理被2gc清除的槽位 else i = nextIndex(i, len); e = tab[i]; } return null; }
7.remove
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; } } }