LinkedHashMap LRU Cache - 确定删除哪些值?

时间:2015-04-29 14:22:28

标签: java caching lru linkedhashset

背景资料

您可以使用LinkedHashMap制作LRU缓存,如at this link所示。基本上,你只是:

  • 扩展链接的哈希映射。
  • 提供容量参数。
  • 使用参数初始化超类(LinkedHashMap),告诉它容量,缩放因子(永远不应该使用),并保持项目的插入/引用顺序。
  • 覆盖removeEldestEntry以在容量被破坏时删除最旧的条目。

我的问题

这是一个非常标准的LRU缓存实现。但有一件事我无法弄清楚如何在LinkedHashMap删除条目时通知它,因为它最近没有使用它。

我知道我可以让removeEldestEntry提供某种形式的通知......但是当有新的插入(放入)底层地图时,有没有办法检索从缓存中删除的元素?或者,有没有办法查询从缓存中删除的最后一项?

1 个答案:

答案 0 :(得分:2)

您可以通过线程本地存储的一些创造性使用来实现它:

class LRUCacheLHM<K,V> extends LinkedHashMap<K,V> {

    private int capacity;

    public LRUCacheLHM(int capacity) {
        //1 extra element as add happens before remove (101), and load factor big
        //enough to avoid triggering resize.  True = keep in access order.
        super(capacity + 1, 1.1f, true);
        this.capacity = capacity;
    }
    private ThreadLocal<Map.Entry<K,V>> removed = new ThreadLocal<Map.Entry<K,V>>();
    private ThreadLocal<Boolean> report = new ThreadLocal<Boolean>();
    {
        report.set(false);
    }
    @Override
    public boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        boolean res = size() > capacity;
        if (res && report.get()) {
            removed.set(eldest);
        }
        return res;
    }
    public Map.Entry<K,V> place(K k, V v) {
        report.set(true);
        put(k, v);
        try {
            return removed.get();
        } finally {
            removed.set(null);
            report.set(false);
        }
    }

}

Demo.

place(K,V)方法背后的想法是向removeEldestEntry发出信号,表示我们希望通过将线程本地report标志设置为true来获取最长条目。当removeEldestEntry看到此标志并知道正在删除某个条目时,它会将最旧的条目放在report变量中,该变量也是线程本地的。

removeEldestEntryput方法的调用发生了对null的调用。之后,最长的条目是report,或者位于准备收获的set(null)变量内。

removed上调用Dictionary<string[], Dictionary<string, float>> data 对于避免延迟内存泄漏非常重要。

相关问题