概念

  LRU(least recently used)就是将最近不被访问的数据给淘汰掉,LRU基于一种假设:认为最近使用过的数据将来被使用的概率也大,最近没有被访问的数据将来被使用的概率比较低。

原理

  LRU一般通过链表形式来存放缓存数据,新插入或被访问的数据放在链表头部,超过一定阈值后,自动淘汰链表尾部的数据。下图很形象的说明了LRU缓存淘汰过程。(图片来自网络)

步骤:

1、新插入A, 将A放置在队列头部

2、新插入B, 将B放置在队列头部, A自动推举次席。

3、新插入C, 将C放置在队列头部, B自动推举次席。

4、新插入D, 将D放置在队列头部, C自动推举次席。

5、新插入E, 将E放置在队列头部, D自动推举次席。

6、新插入E, 将E放置在队列头部, 这时队列长度大于阈值,自动将尾部数据A给淘汰掉

7、访问数据C,然后将C重新放置在队列头部。

8、新插入E, 将E放置在队列头部, 这时队列长度大于阈值,自动淘汰尾部数据B

编码实现LRU策略缓存

/**
* 2018/4/11.
*
* 使用链表+hashmap来实现, 这里没有考虑并发情况, 所以在代码中没有使用锁
*/
public class LRUCache<K, V> { class CacheNode {
public CacheNode before;
public Object key;
public Object value;
public CacheNode after; public CacheNode() {
}
} private HashMap<K, CacheNode> caches;
private int maxCapacity;
private int currentCacheSize;
/**
* 头结点, 头结点不参与淘汰,只是作为标识链表中的第一个节点
*/
private CacheNode head;
/**
* 尾节点, 尾节点不参与淘汰, 只是作为标识链表中最后一个节点
*/
private CacheNode tail; public LRUCache(int maxCapacity) {
this.maxCapacity = maxCapacity;
caches = new HashMap<>(maxCapacity);
head = tail = new CacheNode();
head.after = tail; //对head 的after节点赋值, 防止后续操作出现空指针异常
tail.before = head; // 对tail的before节点赋值, 防止后续操作出现空指针异常
} public void put(K k, V v) {
CacheNode node = caches.get(k);
if (node == null) {
if (currentCacheSize >= maxCapacity) {
caches.remove(tail.before.key); //淘汰尾部的元素
removeLast();
} node = new CacheNode();
node.key = k; currentCacheSize ++;
} node.value = v;
moveToFirst(node); // LRU策略, 新插入的元素放置到队列头部
caches.put(k, node);
} public void moveToFirst(CacheNode node) {
CacheNode n = head.after;
head.after = node;
node.before = head;
n.before = node;
node.after = n;
} public void removeLast() {
CacheNode n = tail.before.before;
n.after = tail;
tail.before = n;
} public Object get(K k) {
CacheNode node = caches.get(k);
if (node == null) {
return null;
} Object v = node.value;
moveToFirst(node);
return v;
} public Object remove(K k) {
CacheNode node = caches.get(k);
if (node == null) {
return null;
} CacheNode pre = node.before;
CacheNode next = node.after;
pre.after = next;
next.before = pre; caches.remove(k); currentCacheSize --;
return node.value;
}
}

上述代码在博主本机测试验证通过(单线程操作下)

最新文章

  1. .NET Core下的日志(3):如何将日志消息输出到控制台上
  2. Servlet容器Tomcat中web.xml中url-pattern的配置详解[附带源码分析]
  3. 插件dTree的使用
  4. jquery 添加节点的几种方法介绍
  5. Android Menu 主菜单是使用
  6. nginx服务器绑定域名和设置根目录
  7. .NET面试题系列
  8. Flume NG中的ElasticSearch Sink
  9. 杭电 HDU 1242 Rescue
  10. C语言盲点笔记1
  11. ASP.NET三剑客 HttpApplication HttpModule HttpHandler 解析
  12. 二、docker的安装和基本命令
  13. 清除被占用的8080端口,否则npm run dev无法正常运行
  14. Python学习day2 while循环&amp;格式化输出&amp;运算符
  15. Linux命令之rpm安装命令
  16. 20170914xlVBA通讯公司分类汇总
  17. 设计模式之单例模式-C++
  18. 【转】深入理解C++的动态绑定和静态绑定 &amp; 不要重定义虚函数中的默认参数
  19. POJ1035&amp;&amp;POJ3080&amp;&amp;POJ1936
  20. MySQL 5.7.19 CentOS 7 安装

热门文章

  1. poj 1637 Sightseeing tour【最大流+欧拉路】
  2. 第三篇(那些JAVA程序BUG中的常见单词)
  3. Linux 虚拟机配置网络
  4. 环境变量解释以及在Linux下的环境变量设置
  5. [POI2001]Gra绿色游戏
  6. Apollo源码搭建调试看一文就够
  7. 《Hadoop高级编程》之为Hadoop实现构建企业级安全解决方案
  8. eval()将json 字符串转换为数组
  9. 【PostgreSQL-9.6.3】启动,登录,退出,关闭
  10. bat 时间 的运算与提取