1. WeakHashMap的适用场景
大部分的缓存都需要占用内存,考虑到内存的有限性,并不能缓存所有的对象,此时就需要用到另类的集合,例如WeakHashMap,可以保存一些对象的同时淘汰另一些对象,以此减少存储成本。
2. 什么是WeakHashMap
WeakHashMap,是在HashMap的基础上多了Weak。表示这是一个弱引用的HashMap。
来看下WeakHashMap的类定义:
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V> {
那WeakHashMap和HashMap有什么区别呢?
3. WeakHashMap和HashMap的区别
在比较WeakHashMap和HashMap的区别之前,先来讲一下弱引用(WeakReference)
关于弱引用
Java有4种引用,强引用(Strong),弱引用(Weak),软引用(soft),虚引用(phantom)。
弱引用表示一个非必需的对象,强度低于软引用,需要通过WeakReference类来间接引用目标对象。被弱引用关联的对象只能存活到下一次垃圾回收发生之前,当触发垃圾回收时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象
注意:如果这个对象还被强引用所引用,那么就不会被回收
简单了解了弱引用之后,我们做一个
总结:
区别于HashMap的强键,WeakHashMap是弱键。
弱键的作用是随时可能被垃圾回收器回收。
4. WeakHashMap的实现原理
主要通过WeakReference和ReferenceQueue实现
来看下源码:
/**
* The entries in this hash table extend WeakReference, using its main ref
* field as the key.
*/
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;
}
@SuppressWarnings("unchecked")
public K getKey() {
return (K) WeakHashMap.unmaskNull(get());
}
public V getValue() {
return value;
}
public V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
- 新建WeakHashMap,将Entry添加到WeakHashMap中,通过数组table保存Entry。
- 弱键在没有被强引用引用的前提下,下一次GC将回收该弱键并添加到ReferenceQueue(queue)队列中。
- 再一次操作WeakHashMap时,会先同步table和queue。table中保存了全部的entry,queue中保存被GC回收的entry;同步它们,就是删除table中被GC回收的键值对。
/**
* 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;
}
}
}
}
WeakHashMap中的大部分操作都会调用expungeStaleEntries()这个方法,储存被gc回收对象的queue会接收gc发送的回收消息,将queue中的key所对应的value赋值null,帮助完成对Entry的回收工作。