我有一个系统,其中对象(为了这个问题的目的,它们是不可变的)是基于请求对象创建的(可以像url或long
一样简单)。它们是使用工厂方法创建的,而不是new
。
如果请求的对象已经存在,那么如果我们可以获得对现有实例的引用,则可以更有效地请求新对象。
为此,我创建了一个名为UniversalCache<K, V>
的课程,因为此时缺少一个更好的名字。它有一个LruCache
,以便保留X个强引用,并HashMap<K, SoftReference<V> >
跟踪所有可能仍然通过系统中的其他强引用保持活动的对象(我是不依赖于SoftReference
保持对象不被GC化。)
当创建一个尚未在缓存中的新对象时,它将与其密钥一起添加到缓存中。要在缓存中搜索它,我使用密钥来获取引用并检查它是否仍然具有对象的引用。
我遇到的问题是如何在对象被垃圾收集后删除这些键/引用对。我不想通过整个HashMap
搜索poll
返回null
的引用。由于指示对象并不总是可用,因此我无法使用它来获取或生成回键。因此,我正在扩展SoftReference
以存储密钥,并使用它从HashMap
中删除该对。这是一个好主意吗?我有一个KeyedSoftReference<K,Rt>
,其中包含与缓存相同类型K
的附加字段(和Rt
最终与V
相同)。< / p>
特别是我想知道在哪里处理ReferenceQueue
(目前在get
中),以及如何投射我从ReferenceQueue.poll()
得到的对象。
这是我到目前为止的代码:
package com.frozenkoi.oss;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import android.util.LruCache;
public class UniversalCache<K, V> {
private final LruCache<K, V> mStrongCache;
private final HashMap<K, KeyedSoftReference<K, V> > mSoftCache;
private final ReferenceQueue<V> mRefQueue;
private static class KeyedSoftReference<K, Rt> extends SoftReference<Rt>
{
private final K mKey;
public KeyedSoftReference(K key, Rt r, ReferenceQueue<? super Rt> q)
{
super(r, q);
mKey = key;
}
public K getKey()
{
return mKey;
}
}
public UniversalCache(int strongCacheMaxItemCount)
{
mStrongCache = new LruCache<K, V>(strongCacheMaxItemCount);
mSoftCache = new HashMap<K, KeyedSoftReference<K, V> >();
mRefQueue = new ReferenceQueue<V>();
}
private void solidify(K key, V value)
{
mStrongCache.put(key, value);
}
public void put(K key, V value)
{
solidify(key, value);
mSoftCache.put(key, new KeyedSoftReference<K, V>(key, value, mRefQueue));
}
public V get(K key)
{
//if it's in Strong container, must also be in soft.
//just check in one of them
KeyedSoftReference<K,? extends V> tempRef = mSoftCache.get(key);
final V tempVal = (null!=tempRef)?tempRef.get():null;
V retVal = null;
if (null == tempVal)
{
mSoftCache.remove(key);
retVal = tempVal;
}
else
{
//if found in LruCache container, must be also in Soft one
solidify(key, tempVal);
retVal = tempVal;
}
//remove expired entries
while (null != (tempRef = (KeyedSoftReference<K,V>)mRefQueue.poll())) //Cast
{
//how to get key from val?
K tempKey = tempRef.getKey();
mSoftCache.remove(tempKey);
}
return retVal;
}
}