LRU 与 LFU ,傻傻分不清楚

  • LRU (Least Recently Used) 最近最少使用,如果数据最近被访问过,那么将来被访问的几率也更高。
  • LFU (Least Frequently Used) 最近最少次数使用,如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小。

LRU缓存

像浏览器的缓存策略、memcached的缓存策略都是使用LRU这个算法,LRU算法会将近期最不会访问的数据淘汰掉。LRU如此流行的原因是实现比较简单,而且对于实际问题也很实用,良好的运行时性能,命中率较高

实现
  • 新数据插入到链表头部
  • 每当缓存命中(即缓存数据被访问),则将数据移到链表头部
  • 当链表满的时候,将链表尾部的数据丢弃
API
set(key,value)

如果key在字典中存在,则先重置对应的value值,然后获取对应的节点curr,将curr节点从链表删除,并移动到链表的头部;

如果key在字典中不存在,则新建一个节点,并将节点放到链表的头部。当cache存满的时候,将链表最后一个节点删除即可。

get(key)

如果key在字典中存在,则把对应的节点放到链表头部,并返回对应的value值;

如果key在字典中不存在,则返回-1

优势
  • 实现简单,使用单链表并对其进行操作即可实现
  • 命中率高

LFU 缓存

相较于 LRU 缓存,LFU 缓存策略更符合热点数据的概念,即让多次被访问的数据缓存效果越好.但是LFU的实现相较于LRU要更为复杂,因为LFU算法除了需要根据访问时间排序外,还需要记录缓存的访问频率.目前市面上很多主流设计中都开始慢慢融入了 LFU 缓存,如 Redis 中的缓存逐出策略,还有Dubbo 中的缓存插件等.

实现

相较于 LRU 算法,LFU 算法实现上还需要记录缓存的访问次数,并按照缓存次数排序,如果访问次序相同的话,则按照访问时间排序。从这个角度来看的话 LFU 算法本身的实现复杂度就要比 LRU 复杂。除此之外,如果缓存的访问频次相同的话 ,LFU 算法就要退化称为 LRU 算法按照缓存的访问时间进行排序。因此又可以将 LFU 算法堪称 LRU的升级版。

按照访问频次进行排序的话用 PriorityQueue 队列实现效果是很好的,该队列内部维护了一个二叉堆,可以保证每次 poll 元素的时候,都可以根据我们的要求,去除当前所有元素的最大值或者最小值。只需要我们呢是心啊实体类中的 Conparable 接口就可以了。

  • 判断新数据是否存在于 优先队列中,如果存在,则取出该元素并更新频次
  • 当缓存满的时候,从优先队列中取出访问频次最低的 n 个元素删除
API
set(key,value)

如果key在字典中存在,则先重置对应的value值,然后更新key的访问时间与访问频次;

如果key在字典中不存在,则保存对应的 value ,然后更新key的访问时间与访问频次。

get(key)

如果key在字典中存在,则更新key的访问时间与访问频次,并返回对应的value值;

如果key在字典中不存在,则返回-1

优势
  • 相较于 LRU 算法,基于频次的缓存汰换策略更加符合热点数据的思想,但实现起来较为复杂

参考资料

LFU五种实现方式,从简单到复杂
LFU 实现思路整理
力扣(LFU缓存)
LRU 实现思路整理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值