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);
}