LRU
选择最近最久未使用的数据予以淘汰。(一种常用的页面置换算法)
谈到LRU我们就不得不说一下Redis的八大淘汰策略
noeviction:不会驱逐任何的key
allkeys-lru:对所有的key使用LRU算法进行删除
volatile-lru:对所有设置了过期时间的key使用LRU算法进行删除
allkeys-random:对所有key随机删除
volatile-random:对所有设置了过期时间的key随机删除
volatile-ttl:删除马上要过期的key
allkeys-lfu:对所有key使用LFU算法进行删除
volatile-lfu:对所有设置了过期时间的key使用LFU算法进行删除
Redis的八大策略用于对Redis本身进行内存优化的策略,通过这一系列的策略可以更好地让Redis存储更多的有用数据,而其中LRU算法更是其中两种策略的核心
核心
关于LRU算法的核心是基于哈希链表(哈希表+双向链表的结合体,时间复杂度O(1))
本质:HashMap+DoubleLinkedList
而当我们在面试的时候有时也会被问到是否能够手写LRU算法,所以基于此,我给出下面两种方式
第一种:参考LinkedHashMap(带有结构顺序的Map),LRU算法的天生实现者
测试结果
第二种:不依赖JDK纯手写
public class LRUDemo {
//缓存的坑位
private int cacheSize;
Map<Integer,Node<Integer,Integer>> map;
DoubleLinkedList<Integer,Integer> doubleLinkedList;
//map负责查找,构建一个虚拟的双向链表,里面安装的就是一个个节点Node,作为数据载体
class Node<K,V>
{
K key;
V value;
Node<K,V> prev;
Node<K,V> next;
public Node(){
this.prev = this.next = null;
}
public Node(K key,V value){
this.key = key;
this.value = value;
this.prev = this.next = null;
}
}
//构造一个虚拟的双向链表,里面安放Node
class DoubleLinkedList<K,V> {
Node<K,V> head; //尾节点
Node<K,V> tail;
public DoubleLinkedList(){
head = new Node<>();
tail = new Node<>();
head.next = tail;
tail.prev = head;
}
//添加到头节点
public void addHead(Node<K,V> node){
node.next = head.next;
node.prev = head;
head.next.prev = node;
head.next = node;
}
//删除节点
public void removeNode(Node<K,V> node){
node.next.prev = node.prev;
node.prev.next = node.next;
node.prev = null;
node.next = null;
}
//获得最后一个节点
public Node getLastNode(){
return tail.prev;
}
}
public int get(int key){
if(!map.containsKey(key)){
return -1;
}
Node<Integer, Integer> node = map.get(key);
doubleLinkedList.removeNode(node);
doubleLinkedList.addHead(node);
return node.value;
}
public void put(int key,int value){
if(map.containsKey(key)){
//相当于更新操作
Node<Integer, Integer> node = map.get(key);
node.value = value;
map.put(key,node);
doubleLinkedList.removeNode(node);
doubleLinkedList.addHead(node);
}else{
//坑位满
if(map.size() == cacheSize){
Node<Integer,Integer> lastNode = doubleLinkedList.getLastNode();
map.remove(lastNode.key);
doubleLinkedList.removeNode(lastNode);
}
Node<Integer, Integer> node = new Node<>(key, value);
map.put(key,node);
doubleLinkedList.addHead(node);
}
}
}
这里就不展示第二种的测试结果了(因为我懒┭┮﹏┭┮),代码应该是没什么问题,感兴趣的话可以尝试自己写一写(●ˇ∀ˇ●)
最后的补充
如何设置Redis的八大策略呢
第一种:命令式
config set maxmemory-policy 策略名
第二种:配置文件
差不多就到这儿吧,如果有什么补充或者疑问,可以留言哈🤭