LRU缓存的Java实现
LRU是Least Recently Used的缩写,即最近最少使用。它将最近一段时间不使用的数据替换掉。LRU算法的提出基于一个事实:在前面几条指令中频繁使用的页面很可能在后面的几条指令中频繁使用。这里使用一个链表结构来保存元素的使用顺序,如果一个元素被使用过,那么它将被放到链表头的下一个节点,如果此时缓存满了,同时也要删除链表尾节点的前一个节点,具体实现如下:
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by CvShrimp on 2018/3/13.
*/
public class LRUCache<Key, Value> {
// 存放缓存内容的Map
private ConcurrentHashMap<Key, Node> cache = new ConcurrentHashMap<>();
// 当前缓存中的元素个数
private int count;
// 缓存的最大存储元素个数
private int capacity;
// 链表头节点
private Node head;
// 链表尾节点
private Node tail;
public LRUCache(int capacity) {
this.capacity = capacity;
this.count = 0;
head = new Node();
tail = new Node();
head.next = tail;
tail.pre = head;
}
// 存放元素顺序的链表类
private class Node {
private Key key;
private Value value;
private Node pre;
private Node next;
public Node(Key key, Value value) {
this.key = key;
this.value = value;
}
public Node() {
}
}
public void set(Key key, Value value) {
Node node = cache.get(key);
if(node == null) {
Node newNode = new Node(key, value);
if(count < capacity) {
// 缓存没满,添加节点
addNode(newNode);
count++;
}else if(count == capacity) {
// 缓存满了,要删除最后一个存放元素的节点
cache.remove(tail.pre.key);
removeNode(tail.pre);
addNode(newNode);
}
cache.put(key, newNode);
}else {
// 如果元素已存在,那么将它移到最前面
moveToHead(node);
cache.put(key, new Node(key, value));
}
}
public Value get(Key key) {
Node node = cache.get(key);
if(node != null) {
moveToHead(node);
return node.value;
}else {
return null;
}
}
private void moveToHead(Node node) {
removeNode(node);
addNode(node);
}
private void addNode(Node node) {
node.pre = head;
node.next = head.next;
head.next.pre = node;
head.next = node;
}
private void removeNode(Node node) {
node.pre.next = node.next;
node.next.pre = node.pre;
}
public static void main(String[] args) {
LRUCache<Integer, String> lruCache = new LRUCache<>(2);
lruCache.set(1, "CvShrimp");
lruCache.set(2, "Zero");
lruCache.get(1);
lruCache.set(3, "Lelouch");
System.out.println(lruCache.cache);
}
}