简体   繁体   English

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

[英]LinkedHashMap LRU Cache - Determine what values are removed?

Background Information 背景资料

You can make a LRU cache with a LinkedHashMap as shown at this link . 您可以使用LinkedHashMap创建LRU缓存,如此链接所示。 Basically, you just: 基本上,你只是:

  • Extend linked hash map. 扩展链接的哈希映射。
  • Provide a capacity parameter. 提供容量参数。
  • Initialize the super class (LinkedHashMap) with parameters to tell it its capacity, scaling factor (which should never be used), and to keep items in insertion/reference order. 使用参数初始化超类(LinkedHashMap)以告诉它容量,缩放因子(永远不应该使用),并使项目保持插入/引用顺序。
  • Override removeEldestEntry to remove the oldest entry when the capacity is breached. 覆盖removeEldestEntry以在容量被破坏时删除最旧的条目。

My Question 我的问题

This is a pretty standard LRU cache implementation. 这是一个非常标准的LRU缓存实现。 But one thing that I can't figure out how to do is how to be notified when the LinkedHashMap removes an entry due to it not being used recently enough. 但是我无法弄清楚如何做的一件事是当LinkedHashMap删除一个条目时如何通知,因为它最近没有被使用。

I know I can make removeEldestEntry provide some form of notification... but is there any way to retrieve the element that is removed from the cache right when a new one is inserted (put) into the underlying map? 我知道我可以让removeEldestEntry提供某种形式的通知......但是当有新的插入(放入)底层地图时,有没有办法检索从缓存中删除的元素? Alternatively, is there a way to query for the last item that was removed from the cache? 或者,有没有办法查询从缓存中删除的最后一项?

You can get it to work with some creative use of thread local storage: 您可以使用线程本地存储的一些创造性使用它:

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. 演示。

The idea behind the place(K,V) method is to signal to removeEldestEntry that we would like to get the eldest entry by setting a thread-local report flag to true . 这个place(K,V)方法背后的想法是通过将线程局部report标志设置为true来向removeEldestEntry发出信号,告知我们想要获得最老的条目。 When removeEldestEntry sees this flag and knows that an entry is being removed, it places the eldest entry in the report variable, which is thread-local as well. removeEldestEntry看到此标志并知道正在删除某个条目时,它会将最旧的条目放在report变量中,该变量也是线程本地的。

The call to removeEldestEntry happens inside the call to the put method. removeEldestEntry的调用发生在对put方法的调用中。 After that the eldest entry is either null , or is sitting inside the report variable ready to be harvested. 之后,最老的条目为null ,或者位于report变量中,准备收获。

Calling set(null) on removed is important to avoid lingering memory leaks. removed调用set(null)对于避免延迟内存泄漏非常重要。

is there any way to retrieve the element that is removed from the cache right when a new one is inserted (put) into the underlying map? 是否有任何方法可以在将新的元素插入(放入)基础地图时检索从缓存中删除的元素?

The removeEldestEntry is notified of the entry to be removed. removeEldestEntry被通知要删除的条目。 You can add a listener which this method calls if you want to make it dynamically configurable. 如果要使其可动态配置,可以添加此方法调用的侦听器。

From the Javadoc 来自Javadoc

protected boolean removeEldestEntry(Map.Entry eldest) protected boolean removeEldestEntry(Map.Entry eldest)

eldest - The least recently inserted entry in the map, or if this is an access-ordered map, the least recently accessed entry. eldest - 地图中最近插入的条目,或者如果这是访问顺序的地图,则是最近访问的条目。 This is the entry that will be removed it this method returns true. 这是将被删除的条目,此方法返回true。 If the map was empty prior to the put or putAll invocation resulting in this invocation, this will be the entry that was just inserted; 如果在put或putAll调用之前映射为空,从而导致此调用,那么这将是刚刚插入的条目; in other words, if the map contains a single entry, the eldest entry is also the newest. 换句话说,如果地图包含单个条目,则最旧的条目也是最新的。

.

is there a way to query for the last item that was removed from the cache? 有没有办法查询从缓存中删除的最后一项?

The last item removed has been removed, however you could have the sub-class store this entry in a field you can retrieve later. 删除的最后一项已被删除,但您可以让子类将此条目存储在您稍后可以检索的字段中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM