手写缓存之Lru缓存淘汰算法


前言

随着近些年大型电商应用(例如京东、阿里巴巴等)的迅速发展,本地缓存和分布式缓存相关技术被大量的应用。那么这些缓存的核心算法都有哪些呢,上次给大家手写了FIFO先进先出算法的实现过程,感兴趣的可以通过手写缓存之FIFO先进先出算法来进行学习和回顾。那么今天给大家介绍的是Lru淘汰缓存算法。手写缓存之FIFO先进先出算法

一、Lru缓存淘汰算法是什么?

Lru算法是近些年来一些大型电商平台比较推荐的一种算法,其原理是在我们的缓存满了以后按照访问数量来进行淘汰,优先淘汰那些访问次数比较低的缓存数据,大家来看下面的示例图来加深理解。

 大家可以从图中看出随着新数据的放入,没有被访问的数据或者访问次数较少的优先被淘汰掉。我们联想一下,当几个商品的数据被频繁访问,那么这些商品的数据就应该被一直保留在缓存中,当缓存满了要放入新的数据的时候,那么就会优先淘汰掉那些访问比较少的数据,来确保我们的缓存里面可以实现比较好的效果,最大程度的缓解数据库的压力。

二、实现步骤

这里和FIFO算法案例一样,先来写一个接口类,并做出实现此接口的实现类,在此基础上我们再去实现Lru算法。

1. 接口

代码如下(示例):

/**
 * Cache规范定义
 */
public interface Cache {
    void putObject(Object key,Object value);
    Object getObject(Object key);
    Object removeObject(Object key);
    void clear();
    int size();
}

2. 接口实现类

代码如下(示例):

/**
 * 简易Cache实现
 * 1)存储结构:散列表(基于JAVA中的hashmap存储)
 * 2)淘汰算法:没有(直到到内存溢出)
 * 3)线程安全:否
 * 4)缓存对对象的引用?强引用
 * 5)对象获取:浅拷贝(获取对象地址)
 */
public class PerpetualCache implements Cache{

    private HashMap<Object,Object> cache=new HashMap<>();
    @Override
    public void putObject(Object key, Object value) {
        cache.put(key, value);
    }

    @Override
    public Object getObject(Object key) {
        return cache.get(key);
    }

    @Override
    public Object removeObject(Object key) {
        return cache.remove(key);
    }

    @Override
    public void clear() {
        cache.clear();
    }

    @Override
    public int size() {
        return cache.size();
    }

    @Override
    public String toString() {
        return "PerpetualCache{" +
                "cache=" + cache.toString() +
                '}';
    }
}

3. Lru淘汰算法实现

代码如下(示例):


/**
 * 基于LRU算法为缓存添加数据淘汰策略。
 */
public class LruCache implements Cache{
    /**关联Cache对象-找到可以存储数据的基层对象*/
    private Cache cache;
    /**定义Cache的最大容量*/
    private int maxCap;
    /**通过LinkedHashMap记录key的访问顺序*/
    private LinkedHashMap<Object,Object> keyAccessOrders;
    /**记录最近访问次数最少的key*/
    private Object eldEstKey;

    public LruCache(Cache cache, int maxCap) {
        this.cache = cache;
        this.maxCap = maxCap;
        keyAccessOrders=new LinkedHashMap<Object,Object>(maxCap,0.75f,true){
            @Override
            protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
                boolean isFull= size()>maxCap;
                if(isFull)eldEstKey=eldest.getKey();//获取最近访问次数最少的key
                return isFull;
            }
        };
    }

    @Override
    public void putObject(Object key, Object value) {
        //1.向Cache中添加新的元素
        cache.putObject(key, value);
        //2.记录key的访问顺序
        keyAccessOrders.put(key, key);
        //3.Cache满了则移除最近访问次数最少的key/value
        if(eldEstKey!=null){
            cache.removeObject(eldEstKey);
            eldEstKey=null;
        }
    }

    @Override
    public Object getObject(Object key) {
        //1.记录key的访问顺序
        keyAccessOrders.get(key);
        //2.返回cache中的指定key对应的value
        return cache.getObject(key);
    }

    @Override
    public Object removeObject(Object key) {
        Object object = cache.removeObject(key);
        keyAccessOrders.remove(key);
        return object;
    }

    @Override
    public void clear() {
           cache.clear();
           keyAccessOrders.clear();
    }

    @Override
    public int size() {
        return cache.size();
    }

    @Override
    public String toString() {
        return "LruCache{" +
                "cache=" + cache.toString() +
                '}';
    }

    public static void main(String[] args) {
        Cache cache=new LruCache(//负责添加算法
                new PerpetualCache(),//负责存数据
                3);
        cache.putObject("A", 100);
        cache.putObject("B", 200);
        cache.putObject("C", 300);
        cache.getObject("A");
        cache.putObject("D", 400);
        cache.putObject("E", 500);
        System.out.println(cache);
    }

}

4. 运行结果演示

期间我们访问了一次A数据 ,当放入D和E之后,没有被访问的B和C被淘汰了,A数据保存了下来并处于头的位置。


总结

通过以上的实现小案例,我们已经初步理解并实现了Lru淘汰算法。相对与FIFO先进先出算法更加智能化,所以被京东这些大型电商平台广泛应用,小伙伴们学会了吗?

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LRU(Least Recently Used)是一种常见的缓存淘汰算法,它的基本思想是:将最不常用的数据最先淘汰掉。 具体实现方式通常是将缓存空间划分为若干个桶(bucket),每个桶中存储一组数据,同时记录它们最后一次被访问的时间。当缓存空间满了,需要淘汰一些数据时,LRU算法会根据数据最近使用的频率和时间进行淘汰算法的核心思想是通过计数器(例如最近访问计数器)和哈希表(或排序列表)来实现。计数器用于记录每个数据项最后一次被访问的时间,哈希表或排序列表用于快速查找和删除数据项。 具体实现步骤如下: 1. 当缓存空间满了,需要淘汰一些数据时,遍历缓存中的所有数据项,并记录它们最后一次被访问的时间。 2. 根据时间戳和计数器的值,将数据项按照最近使用的频率进行排序。 3. 将排名最靠后的数据项从缓存中删除,并释放相应的空间。 4. 如果需要继续淘汰数据,重复步骤1-3,直到缓存空间不再满为止。 这种算法的优点是实现简单,易于理解和实现,并且具有较好的性能和效率。但是,它也有一些缺点,例如当缓存命中率较低时,需要频繁地进行淘汰和替换操作,导致缓存命中率进一步下降。此外,如果需要支持高并发访问,还需要考虑并发控制和线程安全等问题。 总之,LRU算法是一种常用的缓存淘汰算法,适用于需要快速响应和低延迟的应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值