概述
WeakHashMap 类似HashMap ,不同点在WeakHashMap的key是弱引用的key。
谈到弱引用,在这里回顾下四种引用吧
- 强引用:Object obj=new Object()这种,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。
- 软引用: 一般情况不会回收,如果内存不够要溢出时才会进行回收
- 弱引用:当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
- 虚引用:为一个对象设置虚引用的唯一目的只是为了能在这个对象被回收时收到一个系统的通知。
正是因为WeakHashMap使用的是弱引用,它的对象可能随时被回收。WeakHashMap 类的行为部分取决于垃圾回收器的动作,调用两次size()方法返回不同值,调用两次isEmpty(),一次返回true,一次返回false都是可能的。
WeakHashMap工作原理
WeakHashMap具有弱引用的特点:随时被回收对象。
发生GC时,WeakHashMap是如何将Entry移除的呢?
WeakHashMap内部的Entry继承了WeakReference,即弱引用,所以就具有了弱引用的特点,随时可能被回收。看下源码:
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next;
/**
* Creates new entry.
*/
Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
......
WeakHashMap是如何将Entry移除的?
GC每次清理掉一个对象之后,引用对象会放到ReferenceQueue的,接着遍历queue进行删除。WeakHashMap的增删改查操作,就是直接/间接调用expungeStaleEntries()方法,达到及时清除过期entry的目的。可以看下expungeStaleEntries源码
/**
* Expunges stale entries from the table.
*/
private void expungeStaleEntries() {
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;
}
}
}
}