LRU缓存实现

第一种方式,使用LinkedHashMap

package com.lru;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Join
 * @date 2018/4/9 14:41
 */

/**
 * 1. 新数据插入到链表头部;
 2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
 3. 当链表满的时候,将链表尾部的数据丢弃。

 利用LinkedHashMap实现简单的缓存, 必须实现removeEldestEntry方法
 */
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 size()>maxCapacity;
    }

    @Override
    public boolean containsKey(Object key) {
        try {
            lock.lock();
            return super.containsKey(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();
        }
    }
}

第二种实现方式:链表+HashMap

package com.lru;


import java.util.*;

public class LruCache<K,V> {
    private int currentCacheSize;
    private int CacheCapcity;
    private HashMap<K,CacheNode> caches;
    private CacheNode first;
    private CacheNode last;

    public LruCache(int size){
        currentCacheSize=0;
        this.CacheCapcity=size;
        caches=new HashMap <K,CacheNode>(size);

    }

    public void put(K k,V v){
        CacheNode node=caches.get(k);
        if(node==null){
            if(caches.size()>=CacheCapcity){
                caches.remove(last.key);
                removeLast();
            }
            node=new CacheNode();
            node.key=k;
        }

        node.value=v;
        moveToFirst(node);
        caches.put(k,node);

    }


    public Object get(K k){
        CacheNode node=caches.get(k);
        if(node==null){
            return null;
        }
        moveToFirst(node);
        return node.value;
    }

    public Object remove(K k){
        CacheNode node=caches.get(k);
        if(node!=null){
            if(node.pre!=null){
                node.pre.next=node.next;
            }
            if(node.next!=null){
                node.next.pre=node.pre;

            }
            if(node==first){
                first=node.next;
            }
            if(node==last){
                last=node.pre;
            }
        }
        return caches.remove(k);

    }

    public void clear(){
        first=null;
        last=null;
        caches.clear();
    }

    private void moveToFirst(CacheNode node){
        if(first==node){
            return;
        }
        if(node.next!=null){
            node.pre.next=node.next;
        }
        if(node.pre!=null){
            node.pre.next=node.next;
        }
        if(node==last){
            last=last.pre;
        }

        if(first==null||last==null){
            first=last=node;
            return;
        }
        node.next=first;
        first.pre=node;
        first=node;
        first.pre=null;

    }


    public void removeLast(){
        if(last!=null){
            last=last.pre;
            if(last==null){
                first=null;
            }else {
                last.next=null;
            }
        }
    }


    @Override
    public String toString() {
        StringBuilder sb=new StringBuilder();
        CacheNode node=first;
        while (node!= null){
            sb.append(String.format("%s:%s",node.key,node.value));
            node=node.next;
        }
        return sb.toString();

    }
}


class CacheNode {
    CacheNode pre;
    CacheNode next;
    Object key;
    Object value;

    public CacheNode() {

    }

}


测试用例:

public class Test {
    public static void main(String[] args) {

        LruCache<Integer,String> lru = new LruCache<Integer,String>(3);

        lru.put(1, "a");    // 1:a
        System.out.println(lru.toString());
        lru.put(2, "b");    // 2:b 1:a
        System.out.println(lru.toString());
        lru.put(3, "c");    // 3:c 2:b 1:a
        System.out.println(lru.toString());
        lru.put(4, "d");    // 4:d 3:c 2:b
        System.out.println(lru.toString());
        lru.put(1, "aa");   // 1:aa 4:d 3:c
        System.out.println(lru.toString());
        lru.put(2, "bb");   // 2:bb 1:aa 4:d
        System.out.println(lru.toString());
        lru.put(5, "e");    // 5:e 2:bb 1:aa
        System.out.println(lru.toString());
        lru.get(1);         // 1:aa 5:e 2:bb
        System.out.println(lru.toString());
        lru.remove(11);     // 1:aa 5:e 2:bb
        System.out.println(lru.toString());
        lru.remove(1);      //5:e 2:bb
        System.out.println(lru.toString());
        lru.put(1, "aaa");  //1:aaa 5:e 2:bb
        System.out.println(lru.toString());
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容