上一篇讲了有关WeakReference来方便的管理内存,这里来具体分析WeakHashMap。WeakHashMap是一种map,但是在实现的时候,但是这个map中entry会变少。WeakHashMap的设计思路是这样子的,当我们使用WeakHashMap来当做缓存的时候,某些记录可能会在适当的时候会被删除,这样能减少缓存所占用的空间(使用缓存的话,其实softreference更加的妥当,下篇文档讲对softreference进行解释)。
下面看WeakHashMap的代码片段
public V put(K key, V value) {
K k = (K) maskNull(key);
int h = HashMap.hash(k.hashCode());
Entry[] tab = getTable();
int i = indexFor(h, tab.length);
for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
if (h == e.hash && eq(k, e.get())) {
V oldValue = e.value;
if (value != oldValue)
e.value = value;
return oldValue;
}
}
modCount++;
Entry<K,V> e = tab[i];
tab[i] = new Entry<K,V>(k, value, queue, h, e); // 1
if (++size >= threshold)
resize(tab.length * 2);
return null;
}
上面这段代码是WeakHashMap存放记录时候的一个方法,其实方法中没有特别的地方,除了1所标记的,这里的Entry是WeakHashMap自己实现的,下面我看看Entry是怎么实现的。
private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V> { //2
private V value;
private final int hash;
private Entry<K,V> next;
/**
* Creates new entry.
*/
Entry(K key, V value,
ReferenceQueue<K> queue,
int hash, Entry<K,V> next) {
super(key, queue); //3
this.value = value;
this.hash = hash;
this.next = next;
}
public K getKey() {
return WeakHashMap.<K>unmaskNull(get());
}
上面的代码不是Entry的整个,只是Entry的Field部分、一个构造函数和get方法。在2这个地方,我们可以看到Entry是继承了WeakReference,在3中,我们看到了,这里我们把key进行了WeakReference,所以放我们需要这个key的时候,就可以使用上面代码中的get方法。这样,当除了map外没有其他引用指向这个key的时候,这个key就会在gc启动的时候可能被gc掉,然后gc后,指向它的reference就会被放入到queue(这功能是weakreference提供的)。当我们需要使用这个map的时候,就有可能清除掉这个map中不指向key的,也就是被gc掉的reference。如下面代码
private void expungeStaleEntries() {
Entry<K,V> e;
while ( (e = (Entry<K,V>) queue.poll()) != null) {
int h = e.hash;
int i = indexFor(h, 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;
e.next = null; // Help GC
e.value = null; // " "
size--;
break;
}
prev = p;
p = next;
}
}
}
上面代码根据queue中的reference,删除掉map中对应reference的entry。上面的代码在我们对weakHaskMap进行读操作的时候都会执行一遍,如读取WeakHashMap的size
public int size() {
if (size == 0)
return 0;
expungeStaleEntries();
return size;
}
下篇文章主要介绍concurrentHashMap,softreference。