zoukankan      html  css  js  c++  java
  • LRU算法

    LRU算法

    简介

    ​ LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的数据予以淘汰。

    ​ 很多缓存中采用这种算法。

    一:LinkHashMap实现LRU算法

    LinkedHashMap 会对数据使用来排序,这样服务LRU算法的最少使用的思想了

    public class LRUCacheDemo<k, v> extends LinkedHashMap<k, v> {
    
      private int capacity;
    
      public LRUCacheDemo(int capacity) {
        // assesOrder  我们就清楚了当accessOrder设置为false时,会按照插入顺序进行排序,当accessOrder为true是,会按照访问顺序
        super(capacity, 0.75f, true);
        this.capacity = capacity;
      }
      
      @Override
      protected boolean removeEldestEntry(Map.Entry<k, v> eldest) {
        return super.size() > capacity;
      }
    
      public static void main(String[] args) {
        LRUCacheDemo lruCacheDemo = new LRUCacheDemo<>(3);
        lruCacheDemo.put(1, "a");
        lruCacheDemo.put(2, "b");
        lruCacheDemo.put(3, "c");
    
        System.out.println("lruCacheDemo.keySet() = " + lruCacheDemo.keySet());
    
        lruCacheDemo.put(4, "d");
        System.out.println("lruCacheDemo.keySet() = " + lruCacheDemo.keySet());
        
        lruCacheDemo.get(3);
        System.out.println("lruCacheDemo.keySet() = " + lruCacheDemo.keySet());
        
        lruCacheDemo.put(5, "e");
        System.out.println("lruCacheDemo.keySet() = " + lruCacheDemo.keySet());
    
      }
    }
    

    我们定义一个cacheDemo类继承这个LinkedHashMap ,Cache类构造器,提供capacity 参数,作为LRU清理缓存的边界。

    复写removeEldestEntry 方法,当我们缓存的容量达到设定的边界的时候,清理最少使用的缓存。

    特别说明:调用父类构造的时候,有一个参数assesOrder 这个参数的作用就是,当accessOrder设置为false时,会按照插入顺序进行排序,当accessOrder为true是,会按照访问顺序,这里我们最为缓存就设置为true。

    测试结果:

    lruCacheDemo.keySet() = [1, 2, 3]
    lruCacheDemo.keySet() = [2, 3, 4]
    lruCacheDemo.keySet() = [2, 4, 3]
    lruCacheDemo.keySet() = [4, 3, 5]
    

    我们插入a,b,三个值,插入第四个的时候,第一个清理了,当我们访问3的时候,3排队到最后了,2是最少访问的。继续插入5,2就退出了。

    二:手写LRU缓存

    这个模式是借鉴了,AQS同步队列的,通过hash保证访问速度,链表中的头尾节点来记录最近访问,和最少访问的数据。

    package com.leven.demoplus.javase.algorithm;
    
    import java.util.HashMap;
    
    /**
     * 基于lru算法的缓存设计:最近最少使用
     */
    public class LRUCacheDemo2 {
        // 缓存容量
        private int capacity;
        // hashmap用于存数据
        private HashMap<Integer,Node<Integer,Integer>> map;
        // 链表数据结构维护访问次数:1:最近访问的放在头节点 2:缓存容量达到限制的时候,移除链表的尾节
        private DoubleLinkList doubleLinkList;
    
        public LRUCacheDemo2(int capacity) {
            this.capacity = capacity;
            map = new HashMap();
            doubleLinkList = new DoubleLinkList();
        }
    
        public int get(int key){
            if (!map.containsKey(key)){
                return -1;
            }
            Node<Integer, Integer> node = map.get(key);
            // 访问的数据node,移动到链表的头head
            doubleLinkList.removeNode(node);
            doubleLinkList.addHead(node);
            return node.value;
        }
    
        public void  put(Integer key, Integer value){
            if (map.containsKey(key)){
                Node<Integer, Integer> node = map.get(key);
                node.value = value;
    
                // 新加入数据加入头节点
                doubleLinkList.removeNode(node);
                doubleLinkList.addHead(node);
            }else {
                // 缓存空间满了
                if (map.size() >= capacity){
                    // 容量达到限制,淘汰尾节点数据
                    Node lastNode = doubleLinkList.getLastNode();
                    doubleLinkList.removeNode(lastNode);
                    map.remove(lastNode.key);
                }
                Node<Integer, Integer> newNode = new Node<>(key, value);
                map.put(key,newNode);
                doubleLinkList.addHead(newNode);
            }
        }
    
        class DoubleLinkList<k,v>{
           Node<k,v> head;
           Node<k,v> tail;
    
    
            public DoubleLinkList() {
                head = new Node<>();
                tail = new Node<>();
                head.next = tail;
                tail.pre = 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<k,v> getLastNode(){
                return tail.pre;
            }
    
    
        }
    
        class Node<k,v>{
            k key;
            v value;
            Node<k,v> pre;
            Node<k,v> next;
    
            public Node() {
                this.pre = this.next = null;
            }
    
            public Node(k key, v value) {
                this.key = key;
                this.value = value;
            }
        }
    
      public static void main(String[] args) {
          LRUCacheDemo2 lruCacheDemo = new LRUCacheDemo2(3);
          lruCacheDemo.put(1,1);
          lruCacheDemo.put(2, 2);
          lruCacheDemo.put(3, 3);
    
          // 1:预期:容量达到限制,淘汰尾节点1,打印:[1, 2, 3]
          System.out.println("lruCacheDemo.keySet() = " + lruCacheDemo.map.keySet());
    
          // 2:预期:容量达到限制,淘汰尾节点1,打印:[2, 3, 4]
          lruCacheDemo.put(4, 4);
          System.out.println("lruCacheDemo.keySet() = " + lruCacheDemo.map.keySet());
    
          // 3:预期:访问4的数据,最小访问,加入头节点,打印:[2, 3, 4]
          lruCacheDemo.get(2);
          System.out.println("lruCacheDemo.keySet() = " + lruCacheDemo.map.keySet());
    
          // 4:预期:加入5,达到限制,淘汰最久访问的缓存3(如果不执行第三步的话淘汰的应该是2),打印:[2, 4, 5]
          lruCacheDemo.put(5, 5);
          System.out.println("lruCacheDemo.keySet() = " + lruCacheDemo.map.keySet());
      }
    }
    
    

    that is all!!

  • 相关阅读:
    python3监控网站状态
    暴力屏蔽80访问失败的用户
    python3爬取中国药学科学数据
    python3发邮件脚本
    OOP AOP
    lambda
    jni
    Gradle史上最详细解析
    supersocket 遇到的Failed to initialize 和 log4net用法
    在c#中利用keep-alive处理socket网络异常断开的方法
  • 原文地址:https://www.cnblogs.com/simple-flw/p/14883223.html
Copyright © 2011-2022 走看看