0

我有一个系统,其中对象(出于此问题的目的,它们是不可变的)是基于请求对象(可以像 url 或 a 一样简单long)创建的。它们是使用工厂方法创建的,而不是使用new.

如果请求的对象已经存在,那么如果我们可以获取对现有实例的引用,则请求新对象会更有效。

为此,我创建了一个类,目前UniversalCache<K, V>没有更好的名称。它有一个LruCache这样可以保留 X 数量的强引用,以及一个HashMap<K, SoftReference<V> >通过系统中的其他强引用来跟踪可能仍然保持活动状态的所有对象(我不依赖于SoftReference阻止对象成为 GC 'd)。

当创建一个尚未在缓存中的新对象时,它会连同它的键一起添加到缓存中。为了在缓存中搜索它,我使用键来获取引用并检查它是否仍然具有对对象的引用。

我遇到的问题是如何在对象被垃圾收集后删除这些键/引用对。我不想遍历整个HashMap搜索poll返回的引用null。由于所指对象并不总是可用的,因此我无法使用它来获取或生成密钥。所以我正在扩展SoftReference以存储密钥并使用它从HashMap. 这是一个好主意吗?我有一个与缓存KeyedSoftReference<K,Rt>具有相同类型的键的附加字段(最终与 相同)。KRtV

特别是我想就在哪里处理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;
            }

    }
4

0 回答 0