HashMap的弱值(HashMap with weak values)

2019-08-02 19:36发布

我执行持久存储对象的缓存。 我们的想法是:

  • 方法getObjectFromPersistence(long id); ///Takes about 3 seconds getObjectFromPersistence(long id); ///Takes about 3 seconds
  • 方法getObjectFromCache(long id) //Instantly

而且有一个方法: getObject(long id)与以下伪代码:

synchronized(this){
    CustomObject result= getObjectFromCache(id)
    if (result==null){
       result=getObjectFromPersistence(id);
       addToCache(result);
    }
    return result;
}

但是,我需要让CustomObject被垃圾收集器收集。 到现在为止,我使用HashMap<Long,WeakReference<CustomObject>的实施。 问题是,随着时间的HashMap中变得充满空WeakReferences

我检查了WeakHashMap的 ,但在那里的键是弱(和值仍然强引用),因此具有在WeakReferences多头有没有意义。

请告诉我解决这个问题的最佳解决方案? 有一些“逆WeakHashMap中”或类似的东西?

谢谢

Answer 1:

您可以使用番石榴 MapMaker此:

ConcurrentMap<Long, CustomObject> graphs = new MapMaker()
   .weakValues()
   .makeMap();

你甚至可以通过更换运算单元makeMap()与此:

   .makeComputingMap(
       new Function<Long, CustomObject>() {
         public CustomObject apply(Long id) {
           return getObjectFromPersistence(id);
         }
       });

既然你正在编写看起来很像一个高速缓存,更新,更专业的Cache (通过内置CacheBuilder )可能会更贴近您。 它没有实现Map直接接口,但提供了您可能需要为高速缓存更控制。

您可以参考此进行了详细的如何为CacheBuilder工作,这里是快速访问的示例:

LoadingCache<Integer, String> cache = CacheBuilder.newBuilder()
   .maximumSize(100)
   .expireAfterWrite(10, TimeUnit.MINUTES)
   .build(
       new CacheLoader<Integer, String>() {
           @Override
           public String load(Integer id) throws Exception {
               return "value";
           }
       }
   ); 


Answer 2:

WeakReference被添加到它ReferenceQueue被收集它的参考时在施工时提供。

你可以pollReferenceQueue ,每当你访问缓存,并保持一个HashMap<WeakReference<CustomObject>,Long>要知道,如果引用在队列中找到要删除的条目。

或者,如果缓存中不经常使用,你可以观看队列中的一个单独的线程。



Answer 3:

你试过android.util.LruCache (它的一个SDK11类,但它也兼容程序包android.support.v4.util.LruCache )。 它没有实现java.util.Map但就像一个地图,你可以将其定义会多少内存需要,它将(本身未使用的缓存对象)冲洗岁。



Answer 4:

你可以开始“清理” - 在一个线程,同时每一次。 也许,如果你的地图大小超过阈值,但最多每5分钟....类似的东西。

保持清理周期短到不阻断的主要功能。



Answer 5:

您也可以从JBoss的常见测试WeakValueHashMap http://docs.jboss.org/jbossas/javadoc/4.0.2/org/jboss/util/collection/WeakValueHashMap.java.html



Answer 6:

我认为最好的办法(如番石榴上的依赖是不可取的)是使用WeakReference的自定义子类,记住它的ID,让你清除线程可以在WeakReferences在清理过程中去除弱值。

弱引用的实施,有必要的ReferenceQueue和清除线程会是这个样子:

class CustomObjectAccess {

    private static final ReferenceQueue<CustomObject> releasedCustomObjects = 
                                                                  new ReferenceQueue<>();

    static {
        Thread cleanupThread = new Thread("CustomObject cleanup thread")                  
            while (true) {
                CustomObjectWeakReference freed = (CustomObjectWeakReference) 
                                CustomObjectWeakReference.releasedCustomObjects.remove();
                cache.remove(freed.id);
            }
        };
        cleanupThread.start();
    }

    private Map<CustomObjectID, CustomObjectWeakReference> cache;

    public CustomObject get(CustomObjectID id) {
        synchronized(this){
            CustomObject result= getFromCache(id);
            if (result==null) {
                result=getObjectFromPersistence(id);
                addToCache(result);
            }
        }
        return result;
    }

    private addToCache(CustomObject co) {
        cache.put(CustomObject.getID(), new CustomObjectWeakReference(co));
    }

    private getFromCache(CustomObjectID id) {
        WeakReference<CustomObject> weak = cache.get(id);
        if (weak != null) {
            return weak.get();
        }
        return null;
    }

    class CustomObjectWeakReference extends WeakReference<CustomObject> {

        private final CustomObjectID id;

        CustomObjectWeakReference(CustomObject co) {
            super(co, releasedCustomObjects);
            this.id = co.getID();
        }
    }
}


Answer 7:

我有需要存储标记弱对象和揣摩,而不是使用WeakHashMap<String, T>我可以只使用WeakHashMap<T, String>代替。

这是科特林,但应适用于Java的平等:

abstract class InstanceFactory<T> {
    @Volatile
    private var instances: MutableMap<T, String> = WeakHashMap<T, String>()

    protected fun getOrCreate(tag: String = SINGLETON, creator: () -> T): T =
        findByTag(tag)?.let {
            it
        } ?: synchronized(this) {
            findByTag(tag)?.let {
                it
            } ?: run {
                creator().also {
                    instances[it] = tag
                }
            }
        }

    private fun findByTag(tag: String): T? = instances.entries.find { it.value == tag }?.key

    companion object {
        const val SINGLETON = "singleton"
    }
}

这可以使用如下:

class Thing(private val dependency: Dep) { ... }

class ThingFactory(private val dependency: Dep) : InstanceFactory<Thing>() {

    createInstance(tag: String): Thing = getOrCreate(tag) { Thing(dependency) }

}

简单的单身可以做这样的:

object ThingFactory {
    getInstance(dependency: Dependency): Thing = getOrCreate { Thing(dependency) }
}


文章来源: HashMap with weak values