(在学习操作系统时,要做一份有关LRU和clock算法的实验报告,很多同学都应该是通过数组去实现LRU,可能是对堆栈的使用和链表的使用不是很熟悉吧,在网上查资料时看到了LinkedHashMap,于是自己试着用它去实现了LRU.)

LRU算法介绍:

LRU是Least Recently Used 近期最少使用算法。内存管理的一种页面置换算法,对于在内存中但又不用的数据快(内存块)叫做LRU,Oracle会根据那些数据属于LRU而将其移出内存而腾出空间来加载另外的数据,一般用于大数据处理的时候很少使用的数据那么就直接请求数据库,如果经常请求的数据就直接在缓存里面读取。

最近最久未使用(LRU)的页面置换算法,是根据页面调入内存后的使用情况进行决策的。由于无法预测各页面将来的使用情况,只能利用“最近的过去”作为“最近的将来”的近似,因此,LRU置换算法是选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间t,当须淘汰一个页面时,选择现有页面中其t值最大的,即最近最久未使用的页面予以淘汰(可以使用这种方法去实现)。

LRU的实现

可利用一个栈来保存当前使用的各个页面的页面号。每当进程访问某页面时,便将该页面的页面号从栈中移出,将它压入栈顶。因此,栈顶始终是最新被访问页面的编号,而栈底则是最近最久未使用页面的页面号。

LRU算法也可以过双向链表来实现,而LinkedHashMap恰好是通过双向链表实现的java集合类,它的一大特点是,以当某个位置被命中,它就会通过调整链表的指向,将该位置调整到头位置,新加入的内容直接放在链表头,如此一来,最近被命中的内容就向链表头移动,需要替换时,链表最后的位置就是最近最少使用的位置。

假定现有一进程所访问的页面序列为:

4,7,0,7,1,0,1,2,1,2,6

随着进程的访问,栈中页面号的变化情况如图所示。在访问页面6时发生了缺页,此时页面4是最近最久未被访问的页,应将它置换出去。

代码如下:

package 作业;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set; /*LRU是Least Recently Used 近期最少使用算法。
*通过HashLiekedMap实现LRU的算法的关键是,如果map里面的元素个数大于了缓存最大容量,则删除链表头元素
*/ /*public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder)
*LRU参数参数:
*initialCapacity - 初始容量。
*loadFactor - 加载因子(需要是按该因子扩充容量)。
*accessOrder - 排序模式( true) - 对于访问顺序(get一个元素后,这个元素被加到最后,使用了LRU 最近最少被使用的调度算法),对于插入顺序,则为 false,可以不断加入元素。
*/ /*相关思路介绍:
* 当有一个新的元素加入到链表里面时,程序会调用LinkedHahMap类中Entry的addEntry方法,
*而该方法又会 会调用removeEldestEntry方法,这里就是实现LRU元素过期机制的地方,
* 默认的情况下removeEldestEntry方法只返回false,表示可以一直表链表里面增加元素,在这个里 *修改一下就好了。
*
*/ /*
测试数据:
5
11
4 7 0 7 1 0 1 2 1 2 6
*/ import java.util.*;
public class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V>{
private int capacity; //初始内存容量 LRULinkedHashMap(int capacity){ //构造方法,传入一个参数
super(16,0.75f,true); //调用LinkedHashMap,传入参数
this.capacity=capacity; //传递指定的最大内存容量
}
@Override
public boolean removeEldestEntry(Map.Entry<K, V> eldest){
//,每加入一个元素,就判断是size是否超过了已定的容量
System.out.println("此时的size大小="+size());
if((size()>capacity))
{
System.out.println("超出已定的内存容量,把链表顶端元素移除:"+eldest.getValue());
}
return size()>capacity;
} public static void main(String[] args) throws Exception{
Scanner cin = new Scanner(System.in); System.out.println("请输入总共内存页面数: ");
int n = cin.nextInt();
Map<Integer,Integer> map=new LRULinkedHashMap<Integer, Integer>(n); System.out.println("请输入按顺序输入要访问内存的总共页面数: ");
int y = cin.nextInt(); System.out.println("请输入按顺序输入访问内存的页面序列: ");
for(int i=1;i<=y;i++)
{
int x = cin.nextInt();
map.put(x, x);
}
System.out.println("此时内存中包含的页面数是有:");
//用for-each语句,遍历此时内存中的页面并输出
for(java.util.Map.Entry<Integer, Integer> entry: map.entrySet()){
System.out.println(entry.getValue());
}
}
}

实验截图:

用LinkedHashMap实现LRU算法的更多相关文章

  1. LinkedHashMap实现LRU算法

    LinkedHashMap特别有意思,它不仅仅是在HashMap上增加Entry的双向链接,它更能借助此特性实现保证Iterator迭代按照插入顺序(以insert模式创建LinkedHashMap) ...

  2. LinkedHashMap 和 LRU算法实现

    个人觉得LinkedHashMap 存在的意义就是为了实现 LRU 算法. public class LinkedHashMap<K,V> extends HashMap<K,V&g ...

  3. 通过LinkedHashMap实现LRU算法

    一.基于LinkedHashMap源码分析 方法调用流程(这里只是以put方法位例) put() -> putVal() -> afterNodeInsertion() -> rem ...

  4. Java集合详解5:深入理解LinkedHashMap和LRU缓存

    今天我们来深入探索一下LinkedHashMap的底层原理,并且使用linkedhashmap来实现LRU缓存. 摘要: HashMap和双向链表合二为一即是LinkedHashMap.所谓Linke ...

  5. Guava---缓存之LRU算法

    随笔 - 169  文章 - 0  评论 - 292 GuavaCache学习笔记一:自定义LRU算法的缓存实现   前言 今天在看GuavaCache缓存相关的源码,这里想到先自己手动实现一个LRU ...

  6. 借助LinkedHashMap实现基于LRU算法缓存

    一.LRU算法介绍 LRU(Least Recently Used)最近最少使用算法,是用在操作系统中的页面置换算法,因为内存空间是有限的,不可能把所有东西都放进来,所以就必须要有所取舍,我们应该把什 ...

  7. 如何用LinkedHashMap实现LRU缓存算法

    阿里巴巴笔试考到了LRU,一激动忘了怎么回事了..准备不充分啊.. 缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的.LRU这个算法就是把最近一次 ...

  8. JDK自带的LinkedHashMap来实现LRU算法

    1 代码如下 public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> { private final i ...

  9. 基于LinkedhashMap实现的LRU算法

    LRU全称是Least Recently Used,即最近最久未使用的意思.LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小.也就是说,当限定的空间已存 ...

随机推荐

  1. ViewPager的监听事件失效

    主要是因为在我项目使用了PageIndicator,所以这个时候监听事件要写在PageIndicator上. mIndicator.setOnPageChangeListener(new OnPage ...

  2. orm 通用方法——GetOneModel 条件查询一个对象

    数据连接层的方法封装成通用方法是很有必要,节省不必要的重复写代码. Golang的orm.xorm框架没有封装这些操作. 这里是一个查询单个对象的方法. 此处抛砖引玉,大家继续完善. 通用方法定义代码 ...

  3. 30个实用的Linux find命令

    除了在一个目录结构下查找文件这种基本的操作,你还可以用find命令实现一些实用的操作,使你的命令行之旅更加简易.本文将介绍15种无论是于新手还是老鸟都非常有用的Linux find命令 . 首先,在你 ...

  4. [Swift系列]003- 函数

    [基础] Swift函数格式: 1.定义格式: func   函数名(参数名1:数据类型,... ,参数名n:数据类型) -> (返回值类型1,...,返回值类型n){ ///函数体内语句 } ...

  5. 【转】 ARM Linux 3.x的设备树(Device Tree)

    1.    ARM Device Tree起源 http://blog.csdn.net/21cnbao/article/details/8457546 Linus Torvalds在2011年3月1 ...

  6. 切记一定要防止恶意用户直接访问Ajax请求地址

    多年前的一个web项目, 有一个地方是用ajax发送短信验证码, 当时没考虑好, 没判断来路, 这几天被人恶意滥用发送了很多垃圾短信, 投诉到公司来了.  今天一看代码吓出一身冷汗! 以后一定要记得判 ...

  7. HDU 5366 The mook jong (简单DP)

    题意:ZJiaQ希望把木人桩摆在自家的那个由1*1的地砖铺成的1*n的院子里.由于ZJiaQ是个强迫症,所以他要把一个木人桩正好摆在一个地砖上,由于木人桩手比较长,所以两个木人桩之间地砖必须大于等于两 ...

  8. 【英语】Bingo口语笔记(21) - 表达“请客吃饭”

  9. xsheell的下载安装初级使用

    1)关于Xshell 网上更多的资料里提到的SSH客户端是putty,因为简单.开源.免费.但是也正是由于功能过于简单,所以在这里推荐大家使用Xshell. Xshell最初并不能免费使用,而且也没有 ...

  10. github 开源项目

    项目地址: https://github.com/Trinea/android-open-project