WeakHashMap是一个基于Map接话柄现的散列表,实现细节与HashMap雷同(都有负载因子、散列函数等等,但没有HashMap那么多优化手段),它的非凡之处在于每个key都是一个弱引用。
首先我们要大白什么是弱引用,Java将引用分为四类(从JDK1.2开始),强度依次逐渐削弱:
Object obj = new Object()
,这就是一个强引用,强引用只要还存在,就不会被垃圾收集器接纳。finalize()
函数是要靠谱多了。WeakHashMap适适用来当做一个缓存来利用。假设你的缓存系统是基于强引用实现的,那么你就必需以手动(可能用一条线程来不绝轮询)的方法来删除一个无效的缓存项,而基于弱引用实现的缓存项只要没被其他强引用工具关联,就会被直接放入接纳行列。
需要留意的是,只有key是被弱引用关联的,而value一般都是一个强引用工具。因此,需要确保value没有关联到它的key,不然会对key的接纳发生阻碍。在极度的环境下,一个value工具A引用了另一个key工具D,劳务派遣管理系统,而与D相对应的value工具C又反过来引用了与A相对应的key工具B,这就会发生一个引用轮回,导致D与B都无法被正常接纳。想要办理这个问题,就只能把value也酿成一个弱引用,譬喻m.put(key, new WeakReference(value))
,弱引用之间的相互引用不会发生影响。
查找操纵的实现跟HashMap对比简朴了很多,只要读懂了HashMap,根基都能看懂,源码如下:
/** * Value representing null keys inside tables. */ private static final Object NULL_KEY = new Object(); /** * Use NULL_KEY for key if it is null. */ private static Object maskNull(Object key) { return (key == null) ? NULL_KEY : key; } /** * Returns index for hash code h. */ private static int indexFor(int h, int length) { return h & (length-1); } public V get(Object key) { // WeakHashMap答允null key与null value // null key会被替换为一个虚拟值 Object k = maskNull(key); int h = hash(k); Entry<K,V>[] tab = getTable(); int index = indexFor(h, tab.length); Entry<K,V> e = tab[index]; // 遍历链表 while (e != null) { if (e.hash == h && eq(k, e.get())) return e.value; e = e.next; } return null; }
尽量key是一个弱引用,但仍需手动地接纳那些已经无效的Entry。这个操纵会在getTable()
函数中执行,不管是查找、添加照旧删除,都需要挪用getTable()
来得到buckets数组,所以这是种防备内存泄漏的被动掩护法子。
/** * The table, resized as necessary. Length MUST Always be a power of two. */ Entry<K,V>[] table; /** * Reference queue for cleared WeakEntries */ private final ReferenceQueue<Object> queue = new ReferenceQueue<>(); /** * Expunges stale entries from the table. */ private void expungeStaleEntries() { // 遍历ReferenceQueue,然后清理table中无效的Entry for (Object x; (x = queue.poll()) != null; ) { synchronized (queue) { @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>) x; int i = indexFor(e.hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> p = prev; while (p != null) { Entry<K,V> next = p.next; if (p == e) { if (prev == e) table[i] = next; else prev.next = next; // Must not null out e.next; // stale entries may be in use by a HashIterator e.value = null; // Help GC size--; break; } prev = p; p = next; } } } } /** * Returns the table after first expunging stale entries. */ private Entry<K,V>[] getTable() { expungeStaleEntries(); return table; }