LRU Cache 暨LinkedHashMap源码阅读

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

get(key) - Get the value (will always be positive) of the key if the key exists
in the cache, otherwise return -1.

set(key, value) - Set or insert the value if the key is not already present.
When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

题目要求:定义一种数据结构,实现LRU算法(最近最少使用)。

一开始觉得,可以使用LinkedHashMap实现,但没提供按照顺序删除指定范围KEY-VALUE映射的API;后拉,看到了

这篇blog:如何用LinkedHashMap实现LRU缓存算法,才知道如何下手……自己代码看的还是太浅了。

public class LRUCache {
    static class LRULinkedHashMap<K,V> extends java.util.LinkedHashMap<K,V>{
        private int capacity;
        private static final long serialVersionUID = 1L;
        public LRULinkedHashMap(int capacity){
            super(capacity,0.75f,true);
            this.capacity=capacity;
        }
        @Override
        public boolean removeEldestEntry(Map.Entry<K, V> eldest){
            return size()>capacity;
        }
    }

    private LRULinkedHashMap<Integer,Integer> map ;

    public LRUCache(int capacity) {
        map = new LRULinkedHashMap<>(capacity);
    }

    public int get(int key) {
        if(!map.containsKey(key)){
            return -1;
        }
        Integer val = map.get(key);
        return val;
    }

    public void set(int key, int value) {
        map.put(key,value);
    }
}

----------------------------------------------------------------------------------------

先看一下LinkedHashMap的构造器,

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
{

    private static final long serialVersionUID = 3801124242820219131L;

    private transient Entry<K,V> header;

    private final boolean <strong>accessOrder</strong>;

    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }

    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

    public LinkedHashMap() {
        super();
        accessOrder = false;
    }

    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super(m);
        accessOrder = false;
    }

    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

重点在于属性accessOrder表示:

true时,按照KEY-VALUE的访问顺序;

false时,按照KEY-VALUE的插入顺序;

accessOrder可用于保证实现LRU。

/**
     * Returns <tt>true</tt> if this map should remove its eldest entry.
     * This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
     * inserting a new entry into the map.  It provides the implementor
     * with the opportunity to remove the eldest entry each time a new one
     * is added.  This is useful if the map represents a cache: it allows
     * the map to reduce memory consumption by deleting stale entries.
     *
     * <p>Sample use: this override will allow the map to grow up to 100
     * entries and then delete the eldest entry each time a new entry is
     * added, maintaining a steady state of 100 entries.
     * <pre>
     *     private static final int MAX_ENTRIES = 100;
     *
     *     protected boolean removeEldestEntry(Map.Entry eldest) {
     *        return size() > MAX_ENTRIES;
     *     }
     * </pre>
     *
     * <p>This method typically does not modify the map in any way,
     * instead allowing the map to modify itself as directed by its
     * return value.  It <i>is</i> permitted for this method to modify
     * the map directly, but if it does so, it <i>must</i> return
     * <tt>false</tt> (indicating that the map should not attempt any
     * further modification).  The effects of returning <tt>true</tt>
     * after modifying the map from within this method are unspecified.
     *
     * <p>This implementation merely returns <tt>false</tt> (so that this
     * map acts like a normal map - the eldest element is never removed).
     *
     * @param    eldest The least recently inserted entry in the map, or if
     *           this is an access-ordered map, the least recently accessed
     *           entry.  This is the entry that will be removed it this
     *           method returns <tt>true</tt>.  If the map was empty prior
     *           to the <tt>put</tt> or <tt>putAll</tt> invocation resulting
     *           in this invocation, this will be the entry that was just
     *           inserted; in other words, if the map contains a single
     *           entry, the eldest entry is also the newest.
     * @return   <tt>true</tt> if the eldest entry should be removed
     *           from the map; <tt>false</tt> if it should be retained.
     */
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

则保证删除最老(最近未被使用)的元素,只有当返回false时,才生效。

时间: 2024-11-03 01:37:29

LRU Cache 暨LinkedHashMap源码阅读的相关文章

LinkedHashMap源码阅读

LinkedHashMap LinkedHashMap内部采用了散列表和链表实现Map接口,并可以保证迭代的顺序,和HashMap不同,其内部维护一个指向所有元素的双向链表,其决定了遍历的顺序,通常是元素插入的顺序进行迭代,不过元素重新插入顺序不会受到影响. LinkedHashMap提供一个特殊的构造函数,实现了每次迭代返回最近使用的元素,这个特性可以用于构建LRU缓存. 此外removeEldestEntry(Map.Entry)方法可以被子类覆盖用于判断在添加元素的时候什么时候可以删除元素

LinkedHashMap源码阅读笔记(基于jdk1.8)

LinkedHashMap是HashMap的子类,很多地方都是直接引用HashMap中的方法,所以需要注意的地方并不多.关键的点就是几个重写的方法: 1.Entry是继承与Node类,也就是LinkedHashMap与HashMap的根本区别所在,Node是链表形式,只有next与下一个元素进行连接,而Entry的链表有before和after两个连接点. static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,

OSCache源码阅读(二)

前文LRU Cache 暨LinkedHashMap源码阅读提到了如何使用LinkedHashMap来实现一个LRU数据结构,今天在看OSCache代码算法部分的时候,就用到了该知识,what was done contributes what is done now. algorithm包是包含下列缓存过期策略的类: 下面重点介绍LRU和FIFO. LRU private Collection list = new LinkedHashSet(); 使用一个LinkedHashSet对象来实现

LRU、FIFO缓存实现以及LinkedHashMap源码

本篇将描述如何使用LinkedHashMap实现LRU以及FIFO缓存,并将从LinkedHashMap源码层面描述是如何实现这两种缓存的. 1.缓存描述 首先介绍一下FIFO.LRU两种缓存: FIFO(First In First out):先见先出,淘汰最先近来的页面,新进来的页面最迟被淘汰,完全符合队列. LRU(Least recently used):最近最少使用,淘汰最近不使用的页面. 2.代码实现 以下是通过LinkedHashMap实现两种缓存. public class Ca

LRU算法实现,HashMap与LinkedHashMap源码的部分总结

关于HashMap与LinkedHashMap源码的一些总结 JDK1.8之后的HashMap底层结构中,在数组(Node<K,V> table)长度大于64的时候且链表(依然是Node)长度大于8的时候,链表在转换为红黑树时,链表长度小于等于6时将不会进行转化为红黑树.目的是为了保证效率.其中链表的结点只有next,LinkedHashMap是在Entry<K,V>中添加before, after(双向链表的定义),保证可迭代,遍历时为存入顺序. 下面是LinkedHashMap

如何进行高效的源码阅读:以Spring Cache扩展为例带你搞清楚

摘要 日常开发中,需要用到各种各样的框架来实现API.系统的构建.作为程序员,除了会使用框架还必须要了解框架工作的原理.这样可以便于我们排查问题,和自定义的扩展.那么如何去学习框架呢.通常我们通过阅读文档.查看源码,然后又很快忘记.始终不能融汇贯通.本文主要基于Spring Cache扩展为例,介绍如何进行高效的源码阅读. SpringCache的介绍 为什么以Spring Cache为例呢,原因有两个 Spring框架是web开发最常用的框架,值得开发者去阅读代码,吸收思想 缓存是企业级应用开

LinkedHashMap源码分析与LRU实现

LinkedHashMap可认为是哈希表和链接列表综合实现,并允许使用null值和null键.LinkedHashMap实现与HashMap的不同之处在于,LinkedHashMap维护着一个运行于所有条目的双重链接列表.此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序. LinkedHashMap的实现不是同步的.如果多个线程同时访问LinkedHashMap,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步. 1.LinkedHashMap的存储结构   Link

【原】SDWebImage源码阅读(五)

[原]SDWebImage源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 前面的代码并没有特意去讲SDWebImage的缓存机制,主要是想单独开一章节专门讲解缓存.之前我们也遇到一些缓存的属性和方法,比如storeImage.queryDiskCacheForKey.memCache等等. SDWebImage的缓存分为两个部分,一个内存缓存,使用NSCache实现,另一个就是硬盘缓存(disk),使用NSFileManager实现. 不过这么多函数,

Nutch源码阅读进程3---fetch

走了一遍Inject和Generate,基本了解了nutch在执行爬取前的一些前期预热工作,包括url的过滤.规则化.分值计算以及其与mapreduce的联系紧密性等,自我感觉nutch的整个流程是很缜密的,起码从前面两个过程看是这样的. 前期回顾:上一期主要是讲解了nutch的第二个环节Generate,该环节主要完成获取将要抓取的url列表,并写入到segments目录下,其中一些细节的处理包括每个job提交前的输入输出以及执行的map和reducer类具体做了那些工作都可以参考上一篇.接下