zoukankan      html  css  js  c++  java
  • LRU

    LRU是一种缓存淘汰策略,全称是Least Recently Used,即最近最少使用,也就是说我们认为最近使用过的数据应该是是有用的,很久都没用过的数据应该是无用的。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。

    LRU的实现思路就是hashmap+双链表,其中hashmap是为了加速查询, 双链表是为了保存使用状态,当一个缓存项被get, 这个缓存项会被移动到双向链表的头部。 当存储的缓存项超过了指定的capacity,则会从双链表的尾部进行移除。
    Java已经自带了这种数据结构

     1 package test1;
     2 
     3 import java.util.LinkedHashMap;
     4 import java.util.Map;
     5 
     6 public class LRUCache {
     7 
     8     private LinkedHashMap<Integer, Integer> map;
     9     private final int CAPACITY;
    10 
    11     public LRUCache(int capacity) {
    12         CAPACITY = capacity;
    13         map = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) {
    14             @Override
    15             protected boolean removeEldestEntry(Map.Entry eldest) {
    16                 return size() > CAPACITY;
    17             }
    18         };
    19     }
    20 
    21     public int get(int key) {
    22         return map.getOrDefault(key, -1);
    23     }
    24 
    25     public void put(int key, int value) {
    26         map.put(key, value);
    27     }
    28 }
    package test1;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class MyLru<K, V> {
    
        private int capacity;
        private Node head;
        private Node tail;
        private Map<K, Node> map;
    
        public MyLru(int capacity) {
            this.capacity = capacity;
            this.map = new HashMap<>(8);
        }
    
        public void put(K k, V v) {
            // 如果链表为空
            if (head == null) {
                head = new Node(k, v);
                tail = head;
                map.put(k, head);
                return;
            }
            Node node = map.get(k);
            // 如果存在,则提到链表开始, 并更新值
            if (node != null) {
                node.value = v;
                removeToHead(node);
            } else {
                // 否则新建一个节点到开始
                Node newNode = new Node(k, v);
                // 如果长度到了容量,需要去除结尾的节点
                if (map.size() >= capacity) {
                    System.out.println("移除末尾节点:[" + tail.key + "," + tail.value + "]");
                    map.remove(tail.key);
                    tail = tail.prev;
                    tail.next = null;
                }
                // 连到开始
                map.put(k, newNode);
                head.prev = newNode;
                newNode.next = head;
                head = newNode;
            }
        }
    
        /**
         * 访问时,如果缓存有,则返回并把该节点放到最前面
         */
        public V get(K key) {
            Node node = map.get(key);
            if (node == null) {
                return null;
            }
            removeToHead(node);
            return node.value;
        }
    
        private void removeToHead(Node node) {
            if (node == head) {
                return;
            } else if (node == tail) {
                tail = node.prev;
                tail.next = null;
            } else {
                node.prev.next = node.next;
                node.next.prev = node.prev;
            }
            // set node to head
            node.next = head;
            head.prev = node;
            node.prev = null;
            head = node;
        }
    
        class Node {
    
            Node prev;
            Node next;
            K key;
            V value;
    
            public Node(K key, V value) {
                this.key = key;
                this.value = value;
            }
        }
    }

    参考

    https://jimolonely.github.io/2019/05/31/algorithm/003-lru-java/

  • 相关阅读:
    Linux利用crontab命令定时任务
    Linux利用scp命令上传下载文件
    Linux利用ftp命令上传下载文件
    cmd杀死占用端口号的Java进程
    布隆过滤器
    redis缓存穿透、缓存击穿、缓存雪崩
    redis的主从复制master/slaver
    Redis的发布订阅Pub/Sub
    博客园隐藏反对按钮,并简单装饰推荐按钮
    redis事务
  • 原文地址:https://www.cnblogs.com/beyondbit/p/13222194.html
Copyright © 2011-2022 走看看