LRU: Least Recently Used,最近最少使用的淘汰策略;
在redis中最常使用作为数据淘汰策略;
1. 代码实现
package com.test.wei.biz.lru;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 使用双向链表实现LRU过期数据淘汰策略
*
* @author zhangshiwei
* @since 2020年11月27日 下午5:29:18
*/
public class LruTest {
public static void main(String[] args) {
LruCache lruCache = new LruCache(5);
lruCache.set("A", "1");
lruCache.set("B", "2");
lruCache.set("C", "3");
lruCache.set("D", "4");
List<Object> allList = new ArrayList<>();
allList = lruCache.getAll(lruCache.head, allList);
System.out.println("新增后 - allList: " + allList);
lruCache.set("E", "5");
allList = new ArrayList<>();
allList = lruCache.getAll(lruCache.head, allList);
System.out.println("新增后 - allList: " + allList);
lruCache.set("F", "6");
allList = new ArrayList<>();
allList = lruCache.getAll(lruCache.head, allList);
System.out.println("新增后 - allList: " + allList);
lruCache.set("G", "7");
allList = new ArrayList<>();
allList = lruCache.getAll(lruCache.head, allList);
System.out.println("新增后 - allList: " + allList);
LruNode fNode = lruCache.get("F");
System.out.println("从lruCache中读取: " + fNode.key + " - " + fNode.value);
allList = new ArrayList<>();
allList = lruCache.getAll(lruCache.head, allList);
System.out.println("读取后 - allList: " + allList);
}
public static class LruNode {
String key;
Object value;
LruNode pre;
LruNode next;
public LruNode(String key, Object value) {
this.key = key;
this.value = value;
}
}
public static class LruCache {
// 用KV形式存储对象(内部对象维护双向链表), 链表容量, 头结点, 尾节点
private HashMap<String, LruNode> map;
private int capacity;
private LruNode head;
private LruNode tail;
public LruCache(int capacity) {
this.capacity = capacity;
this.map = new HashMap<>(capacity);
}
public void set(String key, Object value) {
System.out.println("新增节点的value:" + value);
LruNode node = map.get(key);
if (node != null) {
node.value = value;
remove(node, false);
} else {
node = new LruNode(key, value);
if (map.size() >= capacity) {
System.out.println("空间不足,删除尾节点: " + tail.value);
remove(tail, true);
}
map.put(key, node);
}
// 新增的元素放在队首
setHead(node);
}
// 移除节点
private void remove(LruNode node, boolean flag) {
if (null != node.pre) {
node.pre.next = node.next;
} else {
head = node.next;
}
if (null != node.next) {
node.next.pre = node.pre;
} else {
tail = node.pre;
}
node.pre = null;
node.next = null;
if (flag) {
map.remove(node.key);
}
}
// 设置头节点
private void setHead(LruNode node) {
if (null != head) {
node.next = head;
head.pre = node;
}
head = node;
if (null == tail) {
tail = node;
}
}
// 根据key获取节点值,并将此节点移动到队首
public LruNode get(String key) {
LruNode node = map.get(key);
if (null != node) {
remove(node, false);
setHead(node);
return node;
}
return null;
}
// 获取所有元素的value值
public List<Object> getAll(LruNode node, List<Object> allList) {
if (null != node) {
allList.add(node.value);
if (null != node.next) {
this.getAll(node.next, allList);
}
}
return allList;
}
}
}
2. 测试结果