设计一个LRU

最近看到一个LRU的讨论,挺赶兴趣的,看了一些文章。自己也手动实现了一个,关键是选择合适的数据结构,然后对这个数据结构进行CRUD。

Java里面实现LRU缓存通常有两种选择,一种是使用LinkedHashMap,一种是自己设计数据结构,使用链表+HashMap

LRU释义

LRU 是 Least Recently Used 的简写,字面意思则是最近最少使用。
通常用于缓存的淘汰策略实现。

实现

LRU 存储是基于双向链表实现的。head 代表双向链表的表头,tail 代表尾部

实现要求

首先预先设置 LRU 的容量,如果存储满了,可以通过 O(1) 的时间淘汰掉双向链表的尾部,每次新增和访问数据,都可以通过 O(1)的效率把新的节点增加到对头,或者把已经存在的节点移动到队头。

实现细节

save(key,value)

  • 当Cache未满时,新的数据项只需插到双链表头部即可。时间复杂度为$O(1)$.
  • 当Cache已满时,将新的数据项插到双链表头部,并删除双链表的尾结点即可。时间复杂度为$O(1)$.

get(key)

每次数据项被查询到时,都将此数据项移动到链表头部

代码

基于LinkedHashMap可以作为底层存储。

//类说明:利用LinkedHashMap实现简单的缓存, 必须实现removeEldestEntry方法,具体参见JDK文档 
public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {

    private final int maxCapacity;

    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

    private final Lock lock = new ReentrantLock();

    public LRULinkedHashMap(int maxCapacity) {
        super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
        this.maxCapacity = maxCapacity;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return super.removeEldestEntry(eldest);
    }//第一种实现removeEldestEntry

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > maxCapacity;
    }//第二种实现removeEldestEntry

    @Override
    public boolean containsKey(Object key) {
        try {
            lock.lock();
            return super.containsKey(key);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public V get(Object key) {
        try {
            lock.lock();
            return super.get(key);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public V put(K key, V value) {
        try {
            lock.lock();
            return super.put(key, value);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public int size() {
        try {
            lock.lock();
            return super.size();
        }finally {
            lock.unlock();
        }
    }

    @Override
    public void clear() {
        try {
            lock.lock();
            super.clear();
        }finally {
            lock.unlock();
        }
    }

    public Collection<Map.Entry<K, V>> getAll() {
        try {
            lock.lock();
            return new ArrayList<Map.Entry<K, V>>(super.entrySet());
        }finally {
            lock.unlock();
        }
    }
}

(完)

发表评论

邮箱地址不会被公开。 必填项已用*标注