缓存基础----LRU算法和FIFO算法的Java实现

Java里面实现LRU缓存算法的通常有两种选择,一种是自己设计数据结构:链表+HashMap(链表用来表示位置,哈希表用来存储和查找),另一种是使用Java中的LinkedHashMap。我们这边文章是使用Java的LinkedHashMap来实现缓存的LRU算法和FIFO算法。

一、LinkedHashMap实现缓存LRU算法

LinkedHashMap有两种数据的存储方式,一种是按照数据的添加顺序存储,另一种是按照数据的访问顺序存储,默认情况下是按照数据的添加顺序存储的。即最近读取的数据放在链表头部,最早读取的数据放在链表尾部。并且LinkedHashMap还有一个判断是否删除老数据的方法,默认返回false,即不删除数据。我们通过LinkedHashMap实现LRU缓存就是继承LinkedHashMap类并重写父类的removeEldestEntry方法。代码如下:

/**
 * LinkedHashMap实现LRU算法
 * @author Administrator
 *
 */
public class CacheLRU<K, V> extends LinkedHashMap<K, V>
{
    private static final long serialVersionUID = 1L;
    
    /*
     * 元素最大值,当数据个数超过最大值时,就要删除一些很久没有被访问到的数据
     */
    private final int MAX_CACHE_SIZE;
    
    /**
     * CacheLRU构造函数,调用父类LinkedHashMap的构造函数
     * @param cacheSize 缓存数据的最大值
     */
    public CacheLRU(int cacheSize) {
        /*
         * 调用父类构造函数,当参数accessOrder为true时,即会按照访问顺序排序,最近访问的放在最前,最早访问的放在后面
         * (int) Math.ceil(cacheSize / 0.75) + 1  计算LinkedHashMap的初始化容量
         */
        super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
        //元素最大值
        MAX_CACHE_SIZE = cacheSize;
    }
    
    /**
     * 重写LinkedHashMap的removeEldestEntry方法,removeEldestEntry方法是LinkedHashMap自带的判断是否删除最老元素的方法,默认返回false,即不删除老数据
     */
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        //当linkedhashmap中数据量大于指定的最大值时,返回true,就自动删除老数据
        return size() > MAX_CACHE_SIZE;
    }

}

但是实际使用中这样写还是有些繁琐,更实用的方法时像下面这样写,省去了单独见一个类的麻烦

private final int cacheSize = 100;
Map<String, Integer> map = new LinkedHashMap<String, Integer>((int) Math.ceil(cacheSize/0.75f) + 1, 0.75f, true) {
    @Override
    protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
    return size() > cacheSize;
    }
};

二、LinkedHashMap实现缓存FIFO算法

FIFO算法的核心思想是先进先出,即按照添加顺序最先添加的数据最先被删除。默认情况下LinkedHashMap就是按照数据的添加顺序存储的,所以实现FIFO算法时,我们只需重写下removeEldestEntry方法即可轻松实现一个FIFO缓存算法。代码如下:

public class CacheFIFO<K, V> extends LinkedHashMap<K, V>
{
    private static final long serialVersionUID = 1L;
    
    /*
     * 元素最大值,当数据个数超过最大值时,就要删除一些很久没有被访问到数据
     */
    private final int MAX_CACHE_SIZE;
    
    /**
     * CacheFIFO构造函数,这里不用调用父类的LinkedHashMap构造函数
     * FIFO原则就是先进先出的,默认情况下LinkedHashMap就是按照添加顺序保存,所以不需要更改排序方式,只需要重写removeEldestEntry方法即可
     * @param cacheSize 缓存数据的最大值
     */
    public CacheFIFO(int cacheSize) {
        this.MAX_CACHE_SIZE = cacheSize;
    }
    
    /**
     * 重写LinkedHashMap的removeEldestEntry方法,removeEldestEntry方法是LinkedHashMap自带的判断是否删除最老元素的方法,默认返回false,即不删除老数据
     */
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        //当linkedhashmap中数据量大于指定的最大值时,返回true,就自动删除老数据
        return size() > MAX_CACHE_SIZE;
    }

}

简化版的实现代码如下:

private final int cacheSize = 5;
LinkedHashMap<String, Integer> lru = new LinkedHashMap<String, Integer>() {
    @Override
    protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
    return size() > cacheSize;
    }
};

三、调用示例

测试代码如下:

public class CacheLRUTest
{

    public static void main(String[] args)
    {
        System.out.println("===========================LRU LinkedHashMap实现开始===========================");
        CacheLRU<String, Integer> lru = new CacheLRU<String, Integer>(5);
        //存入数据,最大值为5
        for(int i=0; i<5; i++) {
            lru.put("test"+i, i);
        }
        System.out.println("目前所有缓存为:" +lru.toString());
        //最近访问的几个数据
        lru.get("test0");
        lru.get("test3");
        lru.get("test3");
        lru.get("test4");
        //新添加两个数据
        lru.put("test5", 5);
        lru.put("test6", 6);
        System.out.println("删除老数据后所有缓存为:" +lru.toString());
        System.out.println("===========================LRU LinkedHashMap实现结束===========================");
        System.out.println();

        System.out.println();
        System.out.println("===========================FIFO LinkedHashMap实现开始===========================");
        CacheFIFO<String, Integer> fifo = new CacheFIFO<String, Integer>(5);
        //存入数据,最大值为5
        for(int i=0; i<5; i++) {
            fifo.put("test"+i, i);
        }
        System.out.println("目前所有缓存为:" +fifo.toString());
        //最近访问的几个数据
        fifo.get("test1");
        fifo.get("test1");
        fifo.get("test2");
        fifo.get("test3");
        //新添加两个数据
        fifo.put("test5", 5);
        fifo.put("test6", 6);
        System.out.println("删除老数据后所有缓存为:" +fifo.toString());
        System.out.println("===========================FIFO LinkedHashMap实现结束===========================");
    }

}

运行结果如下:

===========================LRU LinkedHashMap实现开始===========================
目前所有缓存为:{test0=0, test1=1, test2=2, test3=3, test4=4}
删除老数据后所有缓存为:{test0=0, test3=3, test4=4, test5=5, test6=6}
===========================LRU LinkedHashMap实现结束===========================


===========================FIFO LinkedHashMap实现开始===========================
目前所有缓存为:{test0=0, test1=1, test2=2, test3=3, test4=4}
删除老数据后所有缓存为:{test2=2, test3=3, test4=4, test5=5, test6=6}
===========================FIFO LinkedHashMap实现结束===========================
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
存储器管理实验,主要围绕着对计算机中的存储器进行管理和优化展开。在设计实验时,可以有以下几个创意点: 1. 分页式虚拟存储管理:实验可以设计一个基于分页式虚拟存储管理的系统。通过模拟操作系统中的页面置换算法,比如LRU(最近最少使用)算法FIFO(先进先出)算法等,让学生对页面置换的过程和机制有更深入的了解。 2. 虚拟内存管理实验:实验可以实现一个简单的虚拟内存管理系统。在实验中,可以设置一定的内存大小,并模拟程序对内存的访问和替换过程。通过调整页面大小、实现页面置换算法等,让学生体验虚拟内存管理的性能优化以及实际应用。 3. 缓存一致性实验:对于多处理器系统,缓存一致性是一个关键的问题。实验可以设计一个基于MESI协议的缓存一致性模拟实验,让学生理解缓存一致性的概念和工作原理,以及掌握处理器间数据一致性的解决方法。 4. 内存分配算法:实验可以设计一个内存分配算法的模拟实验。通过实现不同的分配算法,比如最先适应算法、最佳适应算法和最坏适应算法等,让学生比较不同内存分配算法的优缺点,并对它们的性能进行评估。 5. 动态内存管理实验:实验可以让学生实现一个简单的动态内存管理系统,比如堆内存分配和释放。通过实验,学生可以了解动态内存管理的过程和挑战,以及理解内存泄漏和内存碎片等问题。 通过以上实验的设计与实践,学生可以更好地理解存储器管理的原理和实践,提升对计算机系统中存储器管理的理解和掌握。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值