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;
}