Redis学习:LRU算法JAVA实现(非LinkedHashMap)

303 阅读3分钟

最近在看redis的缓存淘汰策略,其中的LRU算法用JAVA实现了一下,没有用LinkedHashMap,代码如下

public class LRU {
    // 缓存最大长度
    private Integer length;

    // 存放缓存节点的map,用于取值
    private Map<String, DoubleLinkList.Node> map;

    // 缓存双向链表
    private DoubleLinkList doubleLinkList;

    /**
     * 初始化
     */
    public LRU(Integer length) {
        this.length = length;
        this.map = new HashMap<>();
        this.doubleLinkList = new DoubleLinkList();
    }

    /**
     * 获取缓存节点
     */
    public String get(String key) {
        // 获取node节点
        DoubleLinkList.Node keyNode = map.get(key);
        if (keyNode == null) {
            System.out.println("节点"+ key + "不存在");
            return null;
        }
        System.out.println("节点"+ key + "存在, 移到队列头部");
        // 将节点从原来位置删除,加到头部
        doubleLinkList.del(keyNode);
        doubleLinkList.addHead(keyNode);
        return keyNode.getValue();
    }

    /**
     * 添加缓存节点
     */
    public void put(String key, String value) {
        DoubleLinkList.Node existNode = map.get(key);
        // key存在, 则更新key的值,并将节点放入头部
        if (existNode != null) {
            System.out.println("节点" + key + "已存在,移到队列头部");
            existNode.setValue(value);
            doubleLinkList.del(existNode);
            doubleLinkList.addHead(existNode);
        } else { // key不存在,则新增节点
            DoubleLinkList.Node newNode = new DoubleLinkList.Node(key, value);
            System.out.println("节点" + key + "不存在,新增节点");
            if (map.size() == length) {
                // 节点长度已经到达最大长度时,需要删除末尾节点,并将节点加入头部
                DoubleLinkList.Node lastNode = doubleLinkList.getLast();
                System.out.println("缓存队列已达到最大长度,删除末尾节点" + lastNode.getKey());
                doubleLinkList.del(lastNode);
                doubleLinkList.addHead(newNode);
                map.remove(lastNode.getKey());
            } else {
                doubleLinkList.addHead(newNode);
                map.put(key, newNode);
            }
        }
    }

    /**
     * 双向链表实现
     */
    private static class DoubleLinkList {

        // 头部指针,不存值
        private Node head;
        // 尾部指针,不存值
        private Node tail;

        /**
        * 初始化,头尾相连
        **/
        public DoubleLinkList() {
            head = new Node();
            tail = new Node();
            head.setPre(tail);
            head.setNext(tail);
            tail.setNext(head);
            tail.setPre(head);
        }

        /**
         * 添加到双向链表头部
         */
        public void addHead(Node node) {
            Node oldHeadNext = head.getNext();
            oldHeadNext.setPre(node);
            node.setNext(oldHeadNext);
            node.setPre(head);
            head.setNext(node);
        }

        /**
         * 删除节点
         */
        public void del(Node node) {
            Node pre = node.getPre();
            Node next = node.getNext();
            pre.setNext(next);
            next.setPre(pre);
        }

        /**
         * 获取链表末尾节点
         */
        public Node getLast() {
            return tail.getPre();
        }

        /**
         * 双向链表的节点类
         */
        private static class Node {

            private String key;

            private String value;

            private Node pre;

            private Node next;

            public Node() {
                pre = null;
                next = null;
            }

            public Node(String key, String value) {
                this.key = key;
                this.value = value;
                pre = null;
                next = null;
            }

            public String getKey() {
                return key;
            }

            public void setKey(String key) {
                this.key = key;
            }

            public String getValue() {
                return value;
            }

            public void setValue(String value) {
                this.value = value;
            }

            public Node getPre() {
                return pre;
            }

            public void setPre(Node pre) {
                this.pre = pre;
            }

            public Node getNext() {
                return next;
            }

            public void setNext(Node next) {
                this.next = next;
            }

        }

        @Override
        public String toString() {
            String a = "";
            Node node = head.next;
            while (node != null && node != tail) {
                a = a + "【节点:" + node.getKey() +" 值:" + node.getValue() + "】";
                node = node.next;
            }
            return a;
        }
    }


    @Override
    public String toString() {
        return "LRU{" +
                "缓存长度=" + length +
                ", 缓存队列=" + doubleLinkList.toString() +
                '}';
    }

    public static void main(String[] args) {
        System.out.println("初始化……");
        LRU lru = new LRU(3);
        System.out.println(lru);
        System.out.println("加入节点 1 ……");
        lru.put("1","aaa");
        System.out.println(lru);
        System.out.println("加入节点 2 ……");
        lru.put("2","bbb");
        System.out.println(lru);
        System.out.println("加入节点 3 ……");
        lru.put("3","ccc");
        System.out.println(lru);
        System.out.println("加入节点 4 ……");
        lru.put("4","ddd");
        System.out.println(lru);
        System.out.println("加入节点 2 ……");
        lru.put("2","bbbb");
        System.out.println(lru);
        System.out.println("获取节点 3 ……");
        System.out.println(lru.get("3"));
        System.out.println(lru);
    }
}

运行输出如下:

初始化……
LRU{缓存长度=3, 缓存队列=}
加入节点 1 ……
节点1不存在,新增节点
LRU{缓存长度=3, 缓存队列=【节点:1:aaa】}
加入节点 2 ……
节点2不存在,新增节点
LRU{缓存长度=3, 缓存队列=【节点:2:bbb】【节点:1:aaa】}
加入节点 3 ……
节点3不存在,新增节点
LRU{缓存长度=3, 缓存队列=【节点:3:ccc】【节点:2:bbb】【节点:1:aaa】}
加入节点 4 ……
节点4不存在,新增节点
缓存队列已达到最大长度,删除末尾节点1
LRU{缓存长度=3, 缓存队列=【节点:4:ddd】【节点:3:ccc】【节点:2:bbb】}
加入节点 2 ……
节点2已存在,移到队列头部
LRU{缓存长度=3, 缓存队列=【节点:2:bbbb】【节点:4:ddd】【节点:3:ccc】}
获取节点 3 ……
节点3存在, 移到队列头部
ccc
LRU{缓存长度=3, 缓存队列=【节点:3:ccc】【节点:2:bbbb】【节点:4:ddd】}