Redis底层原理 (Redis LRU算法)(三)

LRU缓存淘汰算法

LRU是(Least Recently Used)最近最少使用策略的缩写,是根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

LRU 算法的核心数据结构就是哈希链表,双向链表和哈希表的结合体。其设计思想:就是借助哈希表赋予了链表快速查找的特性,可以快速查找某个 key 是否存在缓存(链表)中,同时可以快速删除、添加节点。

Redis底层原理 (Redis LRU算法)(三)_第1张图片

哈希链表实现LRU

将Cache的所有位置都用双链表连接起来,当一个位置被命中之后,通过调整链表的指向,将该位置调整到链表/尾的位置,新加入的Cache直接加到链表/尾中。

这样,在多次进行Cache操作后,最近被命中的,就会被向链表/尾方向移动,而没有命中的,而向链表/头方向移动,链表/头则表示最近最少使用的Cache。

当需要替换内容时候,链表的/尾节点就是最少被命中的位置,我们只需要淘汰链表这部分即可。

 LRU算法设计:

package com.wang.redis.lru;

import java.util.LinkedHashMap;

public class LRUCache {
    private  Node head;
    private Node end;

    // 哈希map
    private HashMap hashMap;
    //缓存存储上限
    private int limit;

    public LRUCache(int limit){
        this.limit = limit;
        hashMap = new HashMap<>();
    }

    /**
     * 获取节点,更新双向链表中当前节点顺序
     * @param key
     * @return
     */
    public String get(String key){
        Node node = hashMap.get(key);
        if(node == null){
            return null;
        }else{
            // 更新双向链表
            refreshNode(node);
            return node.value;
        }
    }

    /**
     * Map 中已存在,则更新Value,并刷新当前节点
     * Map 中不存在,判断容量,满则删除一个节点; 新建并添加节点。
     * @param key
     * @param value
     */
    public  void put(String key ,String value){
        Node node =  hashMap.get(key);
        if(node == null){
            if(hashMap.size()>= limit){
                String oldKey = removeNode(head);
                hashMap.remove(oldKey);
            }
            node = new Node(key,value);
            hashMap.put(key,node);
            addNode(node);
        }else{
            node.value=value;
            refreshNode(node);
        }
    }

    /**
     * 将指定节点从双向链表中删除
     * @param node
     * @return
     */
    public String removeNode(Node node){
        if(node == end){
            end = end.pre;
            end.next = null;
        }else if (node == head){
            head = head.next;
            head.pre = null;
        }else{
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }
        return node.key;
    }

    /**
     * 尾部插入节点
     * @param node
     */
    public void addNode(Node node){
        if(end != null){
            end.next = node;
            node.pre = end;
            node.next = null;
        }
        end = node;
        if(head == null){
            head = node;
        }
    }

    /**
     * 刷新当前节点位置
     * @param node
     */
    public void refreshNode(Node node){
        if(node == end){
            return ;
        }
        removeNode(node);
        addNode(node);
    }
}
class Node{
    public String  key;
    public String value;
    public Node pre;
    public Node next;
    public Node(String key,String value ){
        this.key=key;
        this.value=value;
    }
}

 

你可能感兴趣的:(redis,数据结构与算法)