手写LRU算法

101 阅读1分钟

LRU是redis的缓存过期淘汰策略(Least Recently Used),最近最少使用的一种算法,选择最久未使用的数据将其淘汰。
redis缓存的淘汰策略有很多:

  • novicition:不会驱逐任何key,这样就会在缓存满的时候报OOM异常
  • allkeys-lru:对所有key使用LRU算法进行删除
  • volatile-lru: 对所有设置了过期时间的key使用LRU算法进行删除
  • allkeys-random: 对所有key随机删除
  • volatile-random: 对所有设置了过期时间的key随机删除
  • volatile-ttl:删除马上要过期的key
  • allkeys-lfu:对所有key使用LFU算法进行删除
  • volatile-lfu: duisuoyoushezhileguoqishijian的key使用LFU算法进行删除
public class LRUCacheDemo{
   //map负责查找,构建一个虚拟的双向链表,双向链表里面是一个个的Node节点

   //构造一个Node节点作为数据的载体
   class Node<K,V>{
   K key;
   V value;
   Node<K,V> pre;
   Node<K,V> next;

   public Node(){
   this.prev = this.next = null;
   }

   public Node(K key,V value){
   this.key = key;
   this.value = value;
   }
   }
   //构造一个虚拟双向链表,里面装的就是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.pre = head;
      head.next.pre = node;
      head.next = node;
   }

   //删除节点
   public void removeNode(Node<K,V> node){
   node.next.pre = node.pre;
   node.pre.next = node.next;
   node.pre = null;
   node.next = null;
   }

   //获取最后一个节点
   public Node getLast(){
   return tail.pre;
   }

   private int cacheSize;
   Map<Integer,Node<Interger,Integer> map;
   DoubleLinkedList<Integer,Integer> doubleLinkedList;

   public LRUCacheDemo(int cacheSize){
    //最多能容纳多少个缓存数
    this.cacheSize = cacheSize;
    map = new HashMap();
    doubleLinkedList = new DoubleLinkedList<>();
   }

   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.getLast();
   map.remove(lastNode.key);
   doubleLinkedList.removeNode(lastNode);
   }
   //新增value逻辑
   Node<Integer,Integer> newNode = new Node<>(key,value);
   map.put(key,newNode);
   doubleLinkedList.addHead(newNode);
   }
}