-
map+雙向鏈表實現,其中雙向鏈表頭結點的後繼節點依次存儲最近使用的緩存數據,尾節點的前驅節點爲最久未被使用的數據;當通過key查詢緩存在map中,則將對應節點移動至頭結點的後面;key不在緩存中時,新建一個節點,並移動至頭結點後面。
-
實現代碼如下所示:
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Map+雙向鏈表實現LRU
*
* @param <V>
*/
public class LRU<V> {
// 緩存的數量
private int capacity = 1024;
// 緩存對應的map
private Map<String, Node<String, V>> table = new ConcurrentHashMap<>();
// 雙向鏈表頭結點
private Node<String, V> head;
// 雙向鏈表尾節點
private Node<String, V> tail;
public LRU(int capacity) {
this();
this.capacity = capacity;
}
public LRU() {
head = new Node<>();
tail = new Node<>();
head.next = tail;
head.pre = null;
tail.pre = head;
tail.next = null;
}
/**
* 獲取緩存
*
* @param key
* @return
*/
public V get(String key) {
// 如果key不在table裏面,說明緩存裏面沒有
Node<String, V> currNode = table.get(key);
if (currNode == null) {
return null;
}
// 如果key存在table裏面,則將key對應的node放到對頭
currNode.pre.next = currNode.next;
currNode.next.pre = currNode.pre;
moveNode2Head(currNode);
return currNode.value;
}
/**
* 將當前節點移動到鏈表尾部
*
* @param currNode
*/
private void moveNode2Head(Node<String, V> currNode) {
// 當前節點存在鏈表中要找到當前節點的位置,並把其刪除
// HEAD->A
currNode.next = head.next;
head.next.pre = currNode;
currNode.pre = head;
head.next = currNode;
}
/**
* 保存緩存
*
* @param key
* @param v
*/
public void put(String key, V v) {
// 如果存在緩存裏面,更新當前node的位置
Node<String, V> currNode = table.get(key);
if (currNode == null) {
// 如果不存在的話,判斷是否超過空間大小,如果超過空間大小,將尾部的節點刪除掉;如果沒有超過空間大小,插入到table裏面
if (table.size() == capacity) {
// 刪除當前節點
table.remove(tail.pre.key);
tail.pre.pre.next = tail;
tail.pre = tail.pre.pre;
}
currNode = new Node();
currNode.key = key;
currNode.value = v;
table.put(key, currNode);
} else {
currNode.pre.next = currNode.next;
currNode.next.pre = currNode.pre;
}
moveNode2Head(currNode);
}
static class Node<K, V> {
private K key;
private V value;
private Node<K, V> pre;
private Node<K, V> next;
}
public static void main(String[] args) {
LRU<Integer> lru = new LRU(20);
for (int i = 0; i < 100; i++) {
lru.put("a", 1);
lru.put("b", 2);
lru.put("c", 3);
Integer a1 = lru.get("a");
lru.put("c", 3);
lru.put("d", 4);
lru.put("e", 5);
Integer a = lru.get("a");
lru.put("e", 6);
lru.put("f", 7);
lru.put("i" + i / 10, i);
}
System.out.println(lru);
while (lru.head != null) {
System.out.println(lru.head.key + "-" + lru.head.value);
lru.head = lru.head.next;
}
}
}