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