为ThreadLocal定制的ThreadLocalMap
ThreadLocalMap是java.lang.ThreadLocal的静态内部类。
ThreadLocalMap表面看起来至少实现类似hashmap的功能,但是仔细分析它却有下面的属性。
首先,它只是尽量的让value保持在哈希值的位置或后面,
其次,它提供了对不同key(这里是ThreadLocal)对象的但hashCode相同的存储的支持。
最后,它对Key的引用是弱引用。这个和WeakHashMap一致。但这个和hashMap有点不一样,hashMap要使用用弱引用的话,
一般是对value进行弱引用的,而不是key.
也许有一天我们在自己的程序中需要类似ThreadLocalMap的功能。
以下是从ThreadLocalMap简化而来的代码:
其中Key对应JDK中的ThreadLocal
class Key { final int hashCode = nextHashCode(); static AtomicInteger nextHashCode = new AtomicInteger(); static final int HASH_INCREMENT = 0x61c88647; static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); } } class ThreadLocalMap { static class Entry extends WeakReference<Key> { Object value; Entry(Key k, Object v) { super(k); value = v; } } //初始值,必须是2的n次方 private static final int INITIAL_CAPACITY = 16; /** * The table, resized as necessary. * table.length MUST always be a power of two. */ private Entry[] table; private int size = 0; /** * The next size value at which to resize. */ private int threshold; // Default to 0 /** * Set the resize threshold to maintain at worst a 2/3 load factor. */ private void setThreshold(int len) { threshold = len * 2 / 3; } 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); } /** * 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(Key firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.hashCode & (INITIAL_CAPACITY - 1); table = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); } private Entry getEntry(Key key) { int i = key.hashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); } private Entry getEntryAfterMiss(Key key, int i, Entry e) { Entry[] tab = table[i]; int len = tab.length; while (e != null) { Key k = e.get(); if (k == key) return e; if (k == null) expungeStaleEntry(i); else i = nextIndex(i, len); e = tab[i]; } return null; } private void set(Key key, Object value) { Entry[] tab = table; int len = tab.length; int i = key.hashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { Key k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); } private void remove(Key key) { Entry[] tab = table; int len = tab.length; int i = key.hashCode & (len-1); for (Entry e = tab; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } } private void replaceStaleEntry(Key key, Object value, int staleSlot) { Entry[] tab = table; int len = tab.length; Entry e; int slotToExpunge = staleSlot; for (int i = prevIndex(staleSlot, len); (e = tab) != null; i = prevIndex(i, len)) if (e.get() == null) slotToExpunge = i; for (int i = nextIndex(staleSlot, len); (e = tab) != null; i = nextIndex(i, len)) { Key k = e.get(); if (k == key) { e.value = value; tab = tab[staleSlot]; tab[staleSlot] = e; // Start expunge at preceding stale entry if it exists if (slotToExpunge == staleSlot) slotToExpunge = i; cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); return; } if (k == null && slotToExpunge == staleSlot) slotToExpunge = i; } // If key not found, put new entry in stale slot tab[staleSlot].value = null; tab[staleSlot] = new Entry(key, value); // If there are any other stale entries in run, expunge them if (slotToExpunge != staleSlot) cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); } /**擦除staleSlot的Entry。 *调整所有不在哈希映射位置的value的位置,让它尽量在哈希映射的位置 */ private int expungeStaleEntry(int staleSlot) { Entry[] tab = table; int len = tab.length; tab[staleSlot].value = null; tab[staleSlot] = null; size--; // Rehash until we encounter null Entry e; int i; for (i = nextIndex(staleSlot, len); (e = tab) != null; i = nextIndex(i, len)) { Key k = e.get(); if (k == null) { e.value = null; tab = null; size--; } else { int h = k.hashCode & (len - 1); if (h != i) { tab = null; // Unlike Knuth 6.4 Algorithm R, we must scan until // null because multiple entries could have been stale. while (tab[h] != null) h = nextIndex(h, len); tab[h] = e; } } } return i; } private boolean cleanSomeSlots(int i, int n) { boolean removed = false; Entry[] tab = table; int len = tab.length; do { i = nextIndex(i, len); Entry e = tab; if (e != null && e.get() == null) { n = len; removed = true; i = expungeStaleEntry(i); } } while ( (n >>>= 1) != 0); return removed; } private void rehash() { expungeStaleEntries(); // Use lower threshold for doubling to avoid hysteresis if (size >= threshold - threshold / 4) 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) { Key k = e.get(); if (k == null) { e.value = null; // Help the GC } else { int h = k.hashCode & (newLen - 1); while (newTab[h] != null) h = nextIndex(h, newLen); newTab[h] = e; count++; } } } setThreshold(newLen); size = count; table = newTab; } private void expungeStaleEntries() { Entry[] tab = table; int len = tab.length; for (int j = 0; j < len; j++) { Entry e = tab[j]; if (e != null && e.get() == null) expungeStaleEntry(j); } } }
    小小菜鸟一枚
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号