前言
在看这篇文章时,看到了里面使用了SoftHashMap类。这个类是Shiro框架中的一个类,博主把这个类拿过来后,又添加了一个新的方法来方便使用。
在看到这个类后,考虑了个问题:
- 会不会发生GC后,SoftHashMap里的Value被回收了,而Key还存在的问题呢?(如果会发生这样的问题的话,我们就无法用Key来判断缓存是否存在了。)
下面我们看一下它是如何处理的。
正文
1,会不会发生GC后,SoftHashMap里的Value被回收了,而Key还存在的问题呢?
答案是:会。
为什么会发生这种事呢?我们先看看源码:
/**
* We define our own subclass of SoftReference which contains
* not only the value but also the key to make it easier to find
* the entry in the HashMap after it's been garbage collected.
*/
private static class SoftValue<V, K> extends SoftReference<V> {
private final K key;
/**
* Constructs a new instance, wrapping the value, key, and queue, as
* required by the superclass.
*
* @param value the map value
* @param key the map key
* @param queue the soft reference queue to poll to determine if the entry had been reaped by the GC.
*/
private SoftValue(V value, K key, ReferenceQueue<? super V> queue) {
super(value, queue);
this.key = key;
}
}
在上面的源码是一个类定义,保存SoftHashMap中的实例,就是上面的SoftValue类型。
这个SoftValue是如何实现的呢?主要是两点:
- 继承了
SoftReference<V>
- 声明一个内部变量key,作为Map中的Key
仔细看一下内部代码,“V”所代表的Value被保存到了SoftReference中,而Key则没有。也就是说,当GC自动回收时,“V”所代表的Value会被回收走,但Key不会。
2,SoftHashMap是如何解决Key不自动清除的问题的呢?
在SoftHashMap类中,有一个方法叫做processQueue
,代码如下:
private void processQueue() {
SoftValue sv;
while ((sv = (SoftValue) queue.poll()) != null) {
//noinspection SuspiciousMethodCalls
map.remove(sv.key); // we can access private data!
}
}
这个方法的作用是,从定义的queue里取得“被回收的SoftValue”,然后通过SoftValue的Key,把被回收的SoftValue从Map里删除掉。(虽然SoftValue被收回了,但SoftValue的Key在Map里还有一个强引用,所以Key没有被回收。)
看一下processQueue被调用的地方,在get、put、containsValue等方法的第一行语句,都调用这个“从Map里清除失效缓存”的方法。也就是说,在执行操作之前,先清除一下失效的缓存,这样就不会出现“Key还在,但Value被清除掉的”情况了。
3,为什么被GC清除掉的缓存会保存到ReferenceQueue里呢?
首先我们先看看ReferenceQueue的作用是什么。
如果构造在“弱/软引用”实例时,把ReferenceQueue当做构造函数参数传给实例的话,在“弱/软引用”被GC清除时,会把被清除的实例的引用放到ReferenceQueue里。
所以ReferenceQueue就是用来装被清除的“弱/软引用”的实例的。
在SoftValue的构造函数中,会使用SoftHashMap中声明的ReferenceQueue来构造SoftValue的实例。代码如下:
private SoftValue(V value, K key, ReferenceQueue<? super V> queue) {
super(value, queue);
this.key = key;
}
通过上面的说明,我们明白了这个SoftHashMap类,是如何解决Key遗留的问题了。
参考:
- ReferenceQueue的使用:文章里的第4部分说明了SoftValue的实现机制