• LRU缓存的java实现


    1. LRU缓存 (Least Recently Used 删除最近未使用缓存)

    在get/put时,将当前结点移到头部; 那么尾部自然是最近未使用的key

    import java.util.Map;
    import java.util.WeakHashMap;
    
    
    /**
     * LRU缓存 (Least Recently Used 删除最近未使用缓存)
     */
    public class LRUCache<TKey, TValue> {
    
        /**
         * 缓存node结构 (双向链接)
         *
         * @param <TKey>   缓存node的key类型
         * @param <TValue> 缓存node的value类型
         */
        private class Node<TKey, TValue> {
            /**
             * 双向链接node的前一个结点
             */
            private Node<TKey, TValue> prev;
    
            /**
             * 双向链接node的后一个结点
             */
            private Node<TKey, TValue> next;
    
            /**
             * 缓存的key
             */
            private TKey key;
    
            /**
             * 缓存的value
             */
            private TValue value;
    
            public Node() {
            }
    
            public Node(TKey key, TValue value) {
                this.key = key;
                this.value = value;
            }
    
            @Override
            public String toString() {
                return "Node{" +
                        "key=" + key +
                        ", value=" + value +
                        '}';
            }
        }
    
        /**
         * 增加Map来存储具体缓存项,来实现O(1)访问
         */
        private final Map<TKey, Node<TKey, TValue>> cache = new WeakHashMap<>();
    
        /**
         * 缓存最大数量
         */
        private final int capacity;
        /**
         * 当前缓存数量
         */
        private int size;
    
        /**
         * 双向链接的header
         */
        private final Node<TKey, TValue> header;
    
        /**
         * 双向链接的tail
         */
        private final Node<TKey, TValue> tail;
    
        /**
         * 获取缓存
         *
         * @param key 缓存key
         * @return 缓存value
         */
        public TValue get(final TKey key) {
            Node<TKey, TValue> node = cache.get(key);
            if (node == null) {
                return null;
            }
            // 移到header
            synchronized (cache) {
                move2Header(node);
            }
    
            return node.value;
        }
    
        /**
         * 添加数据
         *
         * @param key   缓存key
         * @param value 缓存value
         */
        public void put(final TKey key, final TValue value) {
            Node<TKey, TValue> node = cache.get(key);
            if (node == null) {
                synchronized (cache) {
                    if (size >= capacity) {
                        //删除尾部
                        Node<TKey, TValue> expireNode = removeTail();
                        cache.remove(expireNode.key);
                        this.size--;
                    }
    
                    node = insertHeader(key, value);
                    cache.put(key, node);
                    this.size++;
                }
            } else {
                node.value = value;
                synchronized (cache) {
                    move2Header(node);
                }
            }
        }
    
        /**
         * 移除缓存
         *
         * @param key 缓存key
         */
        public void remove(final TKey key) {
            Node<TKey, TValue> node = cache.get(key);
            if (node == null) {
                return;
            }
            synchronized (cache) {
                remove(node);
                this.cache.remove(key);
                this.size--;
            }
        }
    
        /**
         * 添加缓存key/value到链表的header
         *
         * @param key   缓存key
         * @param value 缓存value
         */
        private Node<TKey, TValue> insertHeader(final TKey key, final TValue value) {
            Node<TKey, TValue> node = new Node<>(key, value);
    
            return insertHeader(node);
        }
    
        /**
         * 添加缓存node到链表的header
         *
         * @param node 缓存node
         * @return 缓存node
         */
        private Node<TKey, TValue> insertHeader(final Node<TKey, TValue> node) {
            node.prev = this.header;
            node.next = this.header.next;
            this.header.next.prev = node;
            this.header.next = node;
            return node;
        }
    
        /**
         * 移动缓存node到header
         *
         * @param node 缓存node
         */
        private void move2Header(final Node<TKey, TValue> node) {
            remove(node);
            insertHeader(node);
        }
    
        /**
         * 删除链表尾部
         */
        private Node<TKey, TValue> removeTail() {
            Node<TKey, TValue> node = this.tail.prev;
            remove(node);
            return node;
        }
    
        /**
         * 删除链表的node
         */
        private void remove(final Node<TKey, TValue> node) {
            node.prev.next = node.next;
            node.next.prev = node.prev;
        }
    
        /**
         * 添加缓存node到链表的tail
         *
         * @param key   缓存node的key
         * @param value 缓存node的value
         * @return 缓存node
         */
        private Node<TKey, TValue> putTail(final TKey key, final TValue value) {
            Node<TKey, TValue> node = new Node<>(key, value);
            return putTail(node);
        }
    
        /**
         * 添加缓存node到链表的tail
         *
         * @param node 缓存node
         * @return 缓存node
         */
        private Node<TKey, TValue> putTail(final Node<TKey, TValue> node) {
            node.prev = this.tail.prev;
            node.next = this.tail;
            this.tail.prev.next = node;
            this.tail.prev = node;
            return node;
        }
    
        /**
         * .ctor
         *
         * @param capacity 最大缓存数量
         */
        public LRUCache(final int capacity) {
            this.capacity = capacity;
            this.header = new Node<>();
            this.tail = new Node<>();
            this.header.next = this.tail;
            this.header.prev = null;
            this.tail.prev = this.header;
            this.tail.next = null;
            this.size = 0;
        }
    
        @Override
        public String toString() {
            Node<TKey, TValue> node = this.header.next;
            StringBuilder sb = new StringBuilder();
            sb.append("(size:");
            sb.append(size);
            sb.append(")");
            while (node != this.tail) {
                sb.append(node.key);
                sb.append(":");
                sb.append(node.value);
                sb.append(",");
                node = node.next;
            }
            // sb.append(cache.toString());
            return sb.toString();
        }
    }

    2.测试. 

        public static void main(String[] argv) {
            LRUCache<String, String> cache = new LRUCache<>(4);
            cache.put("key1", "value1");
            System.out.println(cache);
            cache.put("key2", "value2");
            System.out.println(cache);
            cache.put("key3", "value3");
            System.out.println(cache);
            cache.put("key4", "value4");
            System.out.println(cache);
            cache.put("key4", "value44");
            System.out.println(cache);
            cache.put("key5", "value5");
            System.out.println(cache);
        }

    输出:

    (size:1)key1:value1,
    (size:2)key2:value2,key1:value1,
    (size:3)key3:value3,key2:value2,key1:value1,
    (size:4)key4:value4,key3:value3,key2:value2,key1:value1,
    (size:4)key4:value44,key3:value3,key2:value2,key1:value1,
    (size:4)key5:value5,key4:value44,key3:value3,key2:value2,
    
    
  • 相关阅读:
    Table Scan, Index Scan, Index Seek
    Ndo v3.1发布了!
    手动建立强类型DataSet
    <.NET分布式应用程序开发>读书笔记 第十章:Q&A
    HQL语法大全
    IT人才最容易犯的几个错误
    在线查询Windows API
    ODP.NET和System.Data.OracleClient的一些不同
    给PDF文件添加链接和书签
    cegui0.6.0的下载、安装、配置及samples浏览
  • 原文地址:https://www.cnblogs.com/zhshlimi/p/13810421.html
Copyright © 2020-2023  润新知