Java LRU队列
引言
LRU(Least Recently Used)是一种常见的缓存淘汰策略,该策略会优先淘汰最近最少使用的缓存数据。在实际应用中,经常需要使用LRU队列来实现缓存系统,以提高性能和资源利用率。本文将介绍LRU队列的原理及其在Java中的实现方式。
LRU队列原理
LRU队列是一种基于哈希表和双向链表的数据结构,用于实现LRU缓存淘汰策略。其原理如下:
- 使用一个哈希表来存储缓存数据,哈希表的键为缓存的键,值为缓存的值。
- 使用一个双向链表来维护缓存数据的访问顺序,链表头部表示最近访问的数据,链表尾部表示最久未访问的数据。
- 当访问一个缓存数据时,如果数据存在于哈希表中,将其从原来的位置移动到链表头部;如果不存在于哈希表中,将其添加到链表头部,并将其添加到哈希表中。
- 当缓存数据达到一定大小时,需要淘汰链表尾部的数据,即最久未访问的数据。同时,需要从哈希表中删除该数据。
LRU队列实现
下面是一个简单的Java实现LRU队列的示例代码:
import java.util.HashMap;
class LRUCache {
class Node {
int key;
int value;
Node prev;
Node next;
}
private int capacity;
private HashMap<Integer, Node> cache;
private Node head;
private Node tail;
public LRUCache(int capacity) {
this.capacity = capacity;
this.cache = new HashMap<>();
this.head = new Node();
this.tail = new Node();
this.head.next = this.tail;
this.tail.prev = this.head;
}
public int get(int key) {
Node node = cache.get(key);
if (node != null) {
// 将访问的节点移动到链表头部
removeNode(node);
addToHead(node);
return node.value;
}
return -1;
}
public void put(int key, int value) {
Node node = cache.get(key);
if (node != null) {
// 更新节点的值,并将节点移动到链表头部
node.value = value;
removeNode(node);
addToHead(node);
} else {
if (cache.size() >= capacity) {
// 链表尾部的节点为最久未访问的节点,需删除
Node tailNode = tail.prev;
removeNode(tailNode);
cache.remove(tailNode.key);
}
// 添加新节点到链表头部
Node newNode = new Node();
newNode.key = key;
newNode.value = value;
cache.put(key, newNode);
addToHead(newNode);
}
}
private void removeNode(Node node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void addToHead(Node node) {
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
}
流程图
下面是LRU队列的流程图:
st=>start: 开始
op1=>operation: 创建LRU队列
op2=>operation: 访问缓存数据
op3=>operation: 添加缓存数据
op4=>operation: 删除缓存数据
cond1=>condition: 数据存在于哈希表中吗?
op5=>operation: 移动节点到链表头部
op6=>operation: 更新节点的值
op7=>operation: 移动节点到链表头部
op8=>operation: 创建新节点
op9=>operation: 删除链表尾部节点
op10=>operation: 添加新节点到链表头部
e=>end: 结束
st->op1->op2->cond1
cond1(yes)->op5->op2
cond1(no)->op8->op9->op10->op3
op3(right)->op2
op2(right)->op7->op2
op6(right)->op7->op2
op7(right)->op2
op9(right)->op4
op4->op10
op10(right)->op3
op3(no)->e
``