LRU,Least Recently Used,最近最少使用;一种资源管理算法
按照字面的意思,也可以理解为缓存淘汰
算法:最近最少访问的资源,我们就从缓存中淘汰出去,以免长时间占用内存且不经常访问;
首先,我们定义基础的数据结构:
public class LRUCache {
// 自定义链表节点
private static class Node {
String key;
String value;
Node pre;
Node next;
Node(String key, String value) {
this.key = key;
this.value = value;
}
}
// 用于高效访问的HashMap
private Map<String, Node> map = new HashMap<>();
// 阈值,限制资源在内存中的数量
private int limit;
// ------------- 维护一个双向链表
// 链表头节点
private Node head;
// 链表尾节点
private Node tail;
public LRUCache(int limit) {
this.limit = limit;
}
}
下面我们定义外界访问的基础方法:
// 对外调用的put函数,用来向缓存中存入数据(或者更新)
public void put(String key, String value);
// 外部调用函数,获取以key为键的值
public String get(String key);
// 外部调用的函数,用来移除给定的key节点
public void remove(String key);
下面是方法的实现:
/**
* 对外调用的put函数,用来向缓存中存入数据(或者更新)
* @param key
* @param value
*/
public void put(String key, String value) {
Node node = map.get(key);
if(node == null) {
// 如果节点不存在
node = new Node(key, value);
if(map.size() >= limit) {
// 如果size要超出容量限制了,先移除,再添加
removeNode(head);
}
} else {
// 如果节点存在,则更新
node.value = value;
removeNode(node);
}
addNode(node);
}
/**
* 外部调用函数,获取以key为键的值
* @param key
* @return
*/
public String get(String key) {
Node node = map.get(key);
if(node == null) {
return null;
}
String value = node.value;
removeNode(node);
addNode(node);
return value;
}
/**
* 外部调用的函数,用来移除给定的key节点
* @param key
*/
public void remove(String key) {
Node node = map.get(key);
removeNode(node);
}
其中涉及到几个子方法:
removeNode(node); 从链表中删除节点
addNode(node); 添加节点到链表尾部
private void removeNode(Node node) {
if(head == null || tail == null) {
throw new RuntimeException("Cache is empty...");
}
if(node == head) {
// 如果是移除头节点
head = head.next;
if(head != null) {
head.pre.next = null;
head.pre = null;
}
} else if(node == tail) {
// 如果是移除尾节点
tail = tail.pre;
if(tail != null) {
tail.next.pre = null;
tail.next = null;
}
} else {
Node tmp = head;
while(tmp != null) {
if(node == tmp) {
Node pre = node.pre;
Node next = node.next;
node.pre = null;
node.next = null;
pre.next = next;
next.pre = pre;
break;
}
tmp = tmp.next;
}
}
map.remove(node.key);
}
private void addNode(Node node) {
if(head == null || tail == null) {
head = tail = node;
} else {
node.pre = tail;
tail.next = node;
tail = node;
}
map.put(node.key, node);
}