/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, 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; //根据哈希码和数组长度求得元素的放置位置,即Entry数组的下标 int i = key.threadLocalHashCode & (len-1); //从i开始遍历到数组的最后一个Entry(进行线性探索) 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为空,用新的key,value,同时清理历史key=null(弱引用)的旧数据 if (k == null) { replaceStaleEntry(key, value, i); return; } }
tab[i] = new Entry(key, value); int sz = ++size; //如果超过设置的閥值,则需要进行扩容 if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
private void replaceStaleEntry(ThreadLocal<?> key, Object value, int staleSlot) { Entry[] tab = table; int len = tab.length; Entry e;
// Back up to check for prior stale entry in current run. // We clean out whole runs at a time to avoid continual // incremental rehashing due to garbage collector freeing // up refs in bunches (i.e., whenever the collector runs). //向前扫描,查找最前一个无效的slot int slotToExpunge = staleSlot; for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len)) if (e.get() == null) //通过循环遍历,可以定位到最前面的一个无效的slot slotToExpunge = i;
// Find either the key or trailing null slot of run, whichever // occurs first //从i开始遍历到数组的最后一个Entry(进行线性探索) for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal<?> k = e.get();
// If we find key, then we need to swap it // with the stale entry to maintain hash table order. // The newly stale slot, or any other stale slot // encountered above it, can then be sent to expungeStaleEntry // to remove or rehash all of the other entries in run. //找到匹配的key if (k == key) { //更新对应的slot对应的value e.value = value; //与无效的slot进行替换 tab[i] = tab[staleSlot]; tab[staleSlot] = e;
// Start expunge at preceding stale entry if it exists ////如果最早的一个无效的slot和当前的staleSlot相等,则从i作为清理的起点 if (slotToExpunge == staleSlot) slotToExpunge = i; //从slotToExpunge开始做一次连续的清理 cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); return; }
// If we didn't find stale entry on backward scan, the // first stale entry seen while scanning for key is the // first still present in the run. //如果当前的slot已经无效,并且向前扫描过程中没有无效slot,则更新slotToExpunge为当前位置 if (k == null && slotToExpunge == staleSlot) slotToExpunge = i; }
// If key not found, put new entry in stale slot //如果key对应的value在entry中不存在,则直接放一个新的entry tab[staleSlot].value = null; tab[staleSlot] = new Entry(key, value);
// If there are any other stale entries in run, expunge them //如果有任何一个无效的slot,则做一次清理 if (slotToExpunge != staleSlot) cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); }
2.4 斐波那契额散列(Fibonacci散列算法)
下面还是给一段ThreadLocal的源码:
1 2 3 4 5 6 7 8 9
//HASH_INCREMENT是为了让哈希码能均匀的分布在2的N次方的数组里 private static final int HASH_INCREMENT = 0x61c88647;
/** * Returns the next hash code. */ private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); }