技术干货程序员

LinkedHashMap实现LRU缓存

2017-03-20  本文已影响0人  HCherisher

LinkedHashMap实现Map的接口,和HashMap不同的是维持了一个所有entries的双向链表,并持有一个该有序链表的迭代器,并有两个Entry<K,V>引用transient LinkedHashMap.Entry<K,V> head,tail 分别指向链表的首部和尾部,最常使用的元素会放到链表的尾部,链表的头部为最不常用的数据,同时插入一个新元素也会插入到尾部,我们可以用这个特性来实现LRU(最近最不常使用)缓存,下面我们在实现前先简单的对LinkedHashMap的一些特性进行简单介绍:

public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }

accessOrdertrue的时候,在我们访问了一个Entry<K,V>时,我们会调用afterNodeAccess()方法,将我们当前访问的节点放入到链表的末尾,利用这个特性便可以区分谁是最近访问,谁是最近最不常访问元素了

下面我们来看看具体的实现
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/*
 * 为最近最少使用(LRU)缓存策略设计一个数据结构,
 * 它应该支持以下操作:获取数据(get)和写入数据(set)。
 * 获取数据get(key):如果缓存中存在key,则获取其数据值(通常是正数),否则返回-1。
 * 写入数据set(key, value):如果key还没有在缓存中,则写入其数据值。
 * 当缓存达到上限,它应该在写入新数据之前删除最近最少使用的数据用来腾出空闲位置。 
 *
 */
public class LRUCache<K, V>{
    LinkedHashMap<K,V> cache = null;
    private int cacheSize;
    public LRUCache(int cacheSize){
        this.cacheSize = (int) Math.ceil (cacheSize / 0.75f) + 1;  // ceil浮点数向上取整数
        cache = new LinkedHashMap<K,V>(this.cacheSize,0.75f,true){  //boolean accessOrder用来控制访问顺序的,默认设置为false,在访问之后,不会将当前访问的元素插入到链表尾部
          //内部类来重写removeEldestEntry()方法
        @Override
          protected boolean removeEldestEntry (Map.Entry<K, V> eldest){
              System.out.println("size="+size());
              return size() > cacheSize; //当前size()大于了cacheSize便删掉头部的元素
          }
        };
    }
    
    public V get(K key){   //如果使用继承的话就用getE而不是get,防止覆盖了父类的该方法
       return (V) cache.get(key);
    }
    public V set(K key,V value){
       return cache.put(key, value);
    }
    
    public int getCacheSize() {
        return cacheSize;
    }

    public void setCacheSize(int cacheSize) {
        this.cacheSize = cacheSize;
    }
    
    public void printCache(){
        for(Iterator it = cache.entrySet().iterator();it.hasNext();){
            Entry<K,V> entry = (Entry<K, V>)it.next();
            if(!"".equals(entry.getValue())){
                System.out.println(entry.getKey() + "\t" + entry.getValue()); 
            }
        }
        System.out.println("------");
    }
    
    public void PrintlnCache(){
        Set<Map.Entry<K,V>> set = cache.entrySet();
        for(Entry<K,V> entry : set){
            K key = entry.getKey();
            V value = entry.getValue();
            System.out.println("key:"+key+"value:"+value);
        }
        
    }
    
    public static void main(String[] args) {
        LRUCache<String,Integer> lrucache = new LRUCache<String,Integer>(3);
        lrucache.set("aaa", 1);
        lrucache.printCache();
        lrucache.set("bbb", 2);
        lrucache.printCache();
        lrucache.set("ccc", 3);
        lrucache.printCache();
        lrucache.set("ddd", 4);
        lrucache.printCache();
        lrucache.set("eee", 5);
        lrucache.printCache();
        System.out.println("这是访问了ddd后的结果");
        lrucache.get("ddd");
        lrucache.printCache();
        lrucache.set("fff", 6);
        lrucache.printCache();
        lrucache.set("aaa", 7);
        lrucache.printCache();
    }

}

上一篇 下一篇

猜你喜欢

热点阅读