/** * 下一个索引 */ privatestaticintnextIndex(int i, int len){ return ((i + 1 < len) ? i + 1 : 0); }
/** * 上一个索引 */ privatestaticintprevIndex(int i, int len){ return ((i - 1 >= 0) ? i - 1 : len - 1); }
/** * 构造一个最初包含(firstKey, firstValue)的新Map * ThreadLocalMaps是延迟构造的,因此只有在至少要放置一个entry时才创建一个 */ 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); }
/** * 构造一个新Map,其中包括给定父Map中的所有可继承ThreadLocals.仅由createInheritedMap调用 * @param parentMap 与父线程关联的Map */ privateThreadLocalMap(ThreadLocalMap parentMap){ Entry[] parentTable = parentMap.table; int len = parentTable.length; setThreshold(len); table = new Entry[len];
for (int j = 0; j < len; j++) { Entry e = parentTable[j]; if (e != null) { @SuppressWarnings("unchecked") ThreadLocal<Object> key = (ThreadLocal<Object>) e.get(); if (key != null) { Object value = key.childValue(e.value); Entry c = new Entry(key, value); int h = key.threadLocalHashCode & (len - 1); while (table[h] != null) h = nextIndex(h, len); table[h] = c; size++; } } } }
/** * 根据key获取对应的entry * 此方法本身只处理快速路径:直接命中存在key;否则它将中继到getEntryAfterMiss.旨在通过部分使此方法易于操作来最大程度地提高直接打击的性能 * @param key 线程本地对象 * @return 与key对应的entry(如果不存在则返回null) */ private Entry getEntry(ThreadLocal<?> key){ int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); }
/** * 当在其直接哈希槽中找不到密钥时使用的getEntry方法的版本 * @param key 线程本地对象 * @param i 密钥的哈希表的索引 * @param e 哈希表的entry * @return 与key对应的entry(如果不存在则返回null) */ 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); else i = nextIndex(i, len); e = tab[i]; } returnnull; }
// 备份以检查当前运行中是否有过时的entry.我们一次清理整个运行,以避免由于垃圾收集器释放成堆的引用(即每当收集器运行时)而导致的连续增量重新哈希 int slotToExpunge = staleSlot; for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len)) if (e.get() == null) slotToExpunge = i;
// 查找运行的键或尾随空槽,以先到者为准 for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal<?> k = e.get();
// 如果找到key则需要将其与旧entry交换以维护哈希表的顺序.然后可以将新旧插槽或在其上方遇到的任何其他旧插槽发送到expungeStaleEntry,以删除或重新哈希运行中的所有其他条目 if (k == key) { e.value = value;