Java实现简单LRU缓存机制的方法
作者:南擘汪 发布时间:2023-08-11 03:54:49
一、什么是 LRU 算法
就是一种缓存淘汰策略。
计算机的缓存容量有限,如果缓存满了就要删除一些内容,给新内容腾位置。但问题是,删除哪些内容呢?我们肯定希望删掉哪些没什么用的缓存,而把有用的数据继续留在缓存里,方便之后继续使用。
LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。
二、LRU的使用
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
第一步:创建一个长度为2的LRUCache
第二步:cache.put(1, 1);放入key=1,value=1的数据
第三步:cache.put(2,2);放入key = 2,value = 2的数据
(因为2刚使用,所有把2移动到前面)
第四步:cache.get(1);获取key = 1的数据
(因为我们刚使用了1,所以把1移动到前面)
第五步:cache.put(3,3);放入key = 3,value = 3的数据
(因为3刚放进,所以放前面,又因为容量只有2,需要移除原先的1个。只因key = 2是最近最少使用的(key = 1刚get()过),所以移除2。
三、LRU的实现机制
算法:
LRU 缓存机制可以通过哈希表辅以双向链表实现,我们用一个哈希表和一个双向链表维护所有在缓存中的键值对。
1)双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久未使用的。
2)哈希表即为普通的哈希映射(HashMap),通过缓存数据的键映射到其在双向链表中的位置。
一、初始化:
二、cache.put(1,1):
三、cache.put(2,2):
四、cache.get(1):
五、cache.put(3,3):
四、代码如下
import java.io.*;
import java.util.HashMap;
public class test {
public static void main(String args[]) throws IOException {
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
}
}
/**
* 设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put
*/
class LRUCache {
private HashMap<Integer,LinkedNode> cache = new HashMap();//方便通过key快速定位结点
private int size;
private int capacity;
private LinkedNode head,tail;
class LinkedNode{
int key;
int value;
LinkedNode pre;
LinkedNode next;
}
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
head = new LinkedNode();
tail = new LinkedNode();
head.next = tail;
tail.pre = head;
}
/**
* 移除节点
* @param node
*/
private void removeNode(LinkedNode node) {
LinkedNode preNode = node.pre;
LinkedNode nextNode = node.next;
preNode.next = nextNode;
nextNode.pre = preNode;
}
/**
* 添加节点到头部
* @param node
*/
private void addNode(LinkedNode node) {
node.pre = head;
node.next = head.next;
head.next.pre = node;
head.next = node;
}
/**
* 将节点移动到头部
* @param node
*/
private void moveToHead(LinkedNode node) {
removeNode(node);
addNode(node);
}
/**
* 获取数据
* @param key
* @return
*/
public int get(int key) {
LinkedNode node = cache.get(key);
if(node != null) {
moveToHead(node);
}else{
return -1;
}
return node.value;
}
/**
* 写入数据
* @param key
* @param value
*/
public void put(int key, int value) {
LinkedNode node = cache.get(key);
//存在
if(node != null) {
node.value = value;//可能更新数据
moveToHead(node);
}
//不存在
else{
LinkedNode newNode = new LinkedNode();
newNode.key = key;
newNode.value = value;
cache.put(key,newNode);//更新Map
addNode(newNode);//添加结点到头部
size++;//更新结点数
if(size > capacity) {//如果结点数超过容量大小
LinkedNode tailPre = tail.pre;
cache.remove(tailPre.key);//更新Map
removeNode(tailPre);//删除最后一个结点(尾结点的前一个结点)
size--;
}
}
}
}
总结:自己实现的简单LRU总归太简单了,要是想完善或者实现更真实的LRU,不妨参考一下Redis中的LRU。(◔◡◔)
来源:https://blog.csdn.net/Milan_1in/article/details/106327306


猜你喜欢
- 1. System.Char 字符char 是 System.Char 的别名。System.Char 占两个字节,16个二进制位。Syst
- 情景模式的设置大家应当相当熟悉了,但是在Android中如何通过自己的程序进行情景模式的设置呢,情景模
- 一、前言二、案例需求1.编写login.html登录页面,username&password两个输入框2.使用Druid数据库连接池
- 本文实例为大家分享了Android实现双曲线折线图的具体代码,供大家参考,具体内容如下先看一下效果图1.先下载jar包 mpandroidc
- 在一般性开发中,笔者经常看到很多同学在对待java并发开发模型中只会使用一些基础的方法。比如Volatile,synchronized。像L
- 前言每次update Maven Project 的时候,看着进度条寸步难行,心里憋得十分难受,明显阻碍我学习的热情。 maven仓库默认在
- Android N 可以同时显示多个应用窗口。 在手机上,两个应用可以在“分屏”模式中左右并排或上下并排显示。例如,用户可以 在上面窗口聊Q
- 本文实例为大家分享了Android读取手机通讯录联系人到项目的具体代码,供大家参考,具体内容如下一、主界面代码如下:<LinearLa
- 所以对于应用层用着还不是很方便。最近做一个项目顺便就封装了一个调用默认打印机的类。虽说有几个小bug,但对于目前来说,已经满足需求了。以后不
- volatile关键字相信了解Java多线程的读者都很清楚它的作用。volatile关键字用于声明简单类型变量,如int、float、boo
- 报错翻译: compileSdkVersion android-24”需要JDK 1.8或更高版本编译。报错现象如下图:原因:st
- 为了追求更好的用户体验,有时候我们需要一个类似心跳一样跳动着的控件来吸引用户的注意力,这是一个小小的优化需求,但是在 Flutter 里动画
- Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。它与 JSP,Velocity,FreeMaker 等模
- 如果你是想在java目录下创建多级目录,直接新建package,如图输入然后,取消勾选Compact Empty Middle Packag
- Executor接口基于以下方法可以完成增,删,改查以及事务处理等操作。事实上,mybatis中的所有数据库操作是通过调用这些方法实现的。p
- 本文实例为大家分享了Android弹性滑动类Scroller的具体代码,供大家参考,具体内容如下Scroller是什么 Scroller就是
- 前言我们经常会被问到这么一个问题:SpringBoot相对于spring有哪些优势呢?其中有一条答案就是SpringBoot自动注入。那么自
- 在开发过程中,不少有Spring Aop的使用,在面向切面编程时,我们会使用< aop:aspect>;在进行事务管理时,我们会
- 什么是Aop主要介绍springboot中aop的使用,用过Spring框架的都知道,aop是spring框架的两大核心功能之一,还有一个就
- 本文实例讲述了JAVA随机打乱数组顺序的方法。分享给大家供大家参考。具体实现方法如下:import java.util.Random;&nb