zoukankan      html  css  js  c++  java
  • 缓存置换策略-LRU算法

    LRU算法

    LRU算法定义:  

      LRU算法是指最近最少使用算法,意思是LRU认为最近使用过的数据,将来被访问的概率会大,最近没有被访问的数据意味着以后刚问的概率小。

    为何要用LRU算法:

      1、我们的存储空间是有限的,当存储空间满了之后,要删除哪些数据呢,才能会时缓存的命中率高一些呢

      2、LRU算法还是比较简单的。

    算法:

      最常见的算法是使用一个链表来实现

        1)将新数据插入到表头

        2)每当缓存命中时,将数据移动到表头

        3)当l存储空间满了的时候将链表尾部的数据删除

      缺点:链表实现,需要遍历链表找到命中的数据

      java中最简单的LRU算法实现,就是利用jdk的LinkedHashMap。 LinkedHashMap底层就是用的HashMap加双链表实现的,而且本身已经实现了按照访问顺序的存储。此外,LinkedHashMap中本身就实现了一个方法removeEldestEntry用于判断是否需要移除最不常读取的数,方法默认是直接返回false,不会移除元素,所以需要重写该方法。即当缓存满后就移除最不常用的数。(通过覆盖这个方法,加入一定的条件,满足条件返回true。当put进新的值方法返回true时,便移除该map中最老的键和值。)

    算法分析:

      偶发性的、周期性的批量操作(可能不是热点数据)会使临时数据涌入缓存,挤出热点数据,导致LRU热点命中率急剧下降,缓存污染情况比较严重。

      

    public class LRU<K,V> {
     
      private static final float hashLoadFactory = 0.75f;
      private LinkedHashMap<K,V> map;
      private int cacheSize;
     
      public LRU(int cacheSize) {
        this.cacheSize = cacheSize;
        int capacity = (int)Math.ceil(cacheSize / hashLoadFactory) + 1;
        map = new LinkedHashMap<K,V>(capacity, hashLoadFactory, true){
          private static final long serialVersionUID = 1;
     
          @Override
          protected boolean removeEldestEntry(Map.Entry eldest) {
            return size() > LRU.this.cacheSize;
          }
        };
      }
     
      public synchronized V get(K key) {
        return map.get(key);
      }
     
      public synchronized void put(K key, V value) {
        map.put(key, value);
      }
     
      public synchronized void clear() {
        map.clear();
      }
     
      public synchronized int usedSize() {
        return map.size();
      }
     
      public void print() {
        for (Map.Entry<K, V> entry : map.entrySet()) {
          System.out.print(entry.getValue() + "--");
        }
        System.out.println();
      }
    }

     LRU-K算法

      LRU-K算法定义:

        LRU-K中的K代表最近使用的次数,因此LRU可以认为是LRU-1。LRU-K的主要目的是为了解决LRU算法“缓存污染”的问题,其核心思想是将“最近使用过1次”的判断标准扩展为“最近使用过K次”。

      算法实现:

        相比LRU,LRU-K需要多维护一个队列,用于记录所有缓存数据被访问的历史。只有当数据的访问次数达到K次的时候,才将数据放入缓存。当需要淘汰数据时,LRU-K会淘汰第K次访问时间距当前时间最大的数据。详细实现如下:

      1. 数据第一次被访问,加入到访问历史列表;

      2. 如果数据在访问历史列表里后没有达到K次访问,则按照一定规则(FIFO,LRU)淘汰;

      3. 当访问历史队列中的数据访问次数达到K次后,将数据索引从历史队列删除,将数据移到缓存队列中,并缓存此数据,缓存队列重新按照时间排序;

      4. 缓存数据队列中被再次访问后,重新排序;

      5. 需要淘汰数据时,淘汰缓存队列中排在末尾的数据,即:淘汰“倒数第K次访问离现在最久”的数据。

     

  • 相关阅读:
    EL表达式判断
    java反射机制,通过类名获取对象,通过方法名和参数调
    MYSQL删除重复数据
    centos apache 隐藏和伪装 版本信息
    CentOS安装crontab及使用方法
    Samba出现“您可能没有权限使用网络资源”解决方法
    Idea使用备忘
    Jenkins入门教程
    multiple datasource config
    windows环境下PostgreSQL的安装
  • 原文地址:https://www.cnblogs.com/volare/p/12318356.html
Copyright © 2011-2022 走看看