我有一个系统,其中对象(出于此问题的目的,它们是不可变的)是基于请求对象(可以像 url 或 a 一样简单long
)创建的。它们是使用工厂方法创建的,而不是使用new
.
如果请求的对象已经存在,那么如果我们可以获取对现有实例的引用,则请求新对象会更有效。
为此,我创建了一个类,目前UniversalCache<K, V>
没有更好的名称。它有一个LruCache
这样可以保留 X 数量的强引用,以及一个HashMap<K, SoftReference<V> >
通过系统中的其他强引用来跟踪可能仍然保持活动状态的所有对象(我不依赖于SoftReference
阻止对象成为 GC 'd)。
当创建一个尚未在缓存中的新对象时,它会连同它的键一起添加到缓存中。为了在缓存中搜索它,我使用键来获取引用并检查它是否仍然具有对对象的引用。
我遇到的问题是如何在对象被垃圾收集后删除这些键/引用对。我不想遍历整个HashMap
搜索poll
返回的引用null
。由于所指对象并不总是可用的,因此我无法使用它来获取或生成密钥。所以我正在扩展SoftReference
以存储密钥并使用它从HashMap
. 这是一个好主意吗?我有一个与缓存KeyedSoftReference<K,Rt>
具有相同类型的键的附加字段(最终与 相同)。K
Rt
V
特别是我想就在哪里处理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;
}
}