LruCache算法原理及实现
LruCache算法原理及实现
LruCache算法原理
LRU为Least Recently Used的缩写,意思也就是近期最少使用算法。LruCache将LinkedHashMap的顺序设置为LRU顺序来实现LRU缓存,每次调用get并获取到值(也就是从内存缓存中命中),则将该对象移到链表的尾端。调用put插入新的对象也是存储在链表尾端,这样当内存缓存达到设定的最大值时,将链表头部的对象(近期最少用到的)移除。
基于LinkedHashMap的LRUCache的实现,关键是重写LinkedHashMap的removeEldestEntry方法,在LinkedHashMap中该方法默认返回false(LRUCache本身未考虑线程安全的问题),这样此映射的行为将类似于正常映射,即永远不能移除最旧的元素。
LruCache算法实现的思路
- 按从近期访问最少到近期访问最多的顺序(即访问顺序)来保存元素,LinkedHashMap提供了LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)构造函数,该哈希映射的迭代顺序就是最后访问其条目的顺序,这种映射很适合构建LRU缓存。
- LinkedHashMap提供了removeEldestEntry(Map.Entry<K,V> eldest)方法。该方法在每次添加新条目时移除最旧条目,但该方法默认返回false,这样,此映射的行为将类似于正常映射,即永远不能移除最旧的元素。因而需要重写该方法。
基于LinkedHashMap的LruCache具体实现
import java.util.LinkedHashMap;
import java.util.Map;
public class LruCache<K, V> {
private LinkedHashMap<K, V> map;//链表存储对象
private int cacheSize;//cache大小
private int hitCount;//命中次数
private int missCount;//未命中次数
public synchronized final int getCacheSize() {
return cacheSize;
}
public synchronized final int getHitCount() {
return hitCount;
}
public synchronized final int getMissCount() {
return missCount;
}
static final int DEFAULT_CACHE_SIZE = 2;//cache默认大小
public V put(K key, V value) {
return map.put(key, value);
}
public V get(Object key) {
if (null == key) {
throw new NullPointerException(" key == null ");
}
V val = null;
synchronized (this) {
val = map.get(key);
if (null != val) {
hitCount += 1;
return val;
}
missCount += 1;
}
return val;
}
public LruCache() {
this(DEFAULT_CACHE_SIZE);
}
public LruCache(int cacheSize) {
this.cacheSize = cacheSize;
int hashTableSize = (int) (Math.ceil(cacheSize / 0.75f) + 1);
//LruCache算法实现的关键
//1、按从近期访问最少到近期访问最多的顺序(即访问顺序)来保存元素,那么请使用下面的构造方法构造LinkedHashMap
//public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder); //该哈希映射的迭代顺序就是最后访问其条目的顺序,这种映射很适合构建LRU缓存。
//2、LinkedHashMap提供了removeEldestEntry(Map.Entry<K,V> eldest)方法。该方法可以提供在每次添加新条目时移除最旧条目的实现程序,默认返回false,这样,此映射的行为将类似于正常映射,即永远不能移除最旧的元素。
map = new LinkedHashMap<K, V>(hashTableSize, 0.75f, true){
private static final long serialVersionUID = 1L;
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
System.out.println(" ***** size=" + size() + " cacheSize=" + LruCache.this.cacheSize + " ****");
// return super.removeEldestEntry(eldest);
return size() > LruCache.this.cacheSize;
}
};
}
public static void main(String[] args) {
LruCache<String, String> lruCache = new LruCache<String, String>(3);
lruCache.put("1", "1");
lruCache.put("2", "2");
lruCache.put("3", "3");
lruCache.put("4", "4");
lruCache.put("5", "5");
System.out.println("==========================================================================");
System.out.println("hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
System.out.println("==========================================================================");
System.out.println(lruCache.get("1") + " hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
System.out.println(lruCache.get("2") + " hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
System.out.println(lruCache.get("3") + " hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
System.out.println(lruCache.get("4") + " hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
System.out.println(lruCache.get("4") + " hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
System.out.println(lruCache.get("4") + " hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
System.out.println(lruCache.get("4") + " hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
lruCache.put("6", "6");
lruCache.put("7", "7");
System.out.println(lruCache.get("4") + " hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
lruCache.put("8", "8");
System.out.println(lruCache.get("5") + " hitCount=" + lruCache.getHitCount() + " missCount=" + lruCache.getMissCount());
System.out.println("==========================================================================");
for(Map.Entry<String, String> entry : lruCache.map.entrySet()) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
执行结果
***** size=1 cacheSize=3 ****
***** size=2 cacheSize=3 ****
***** size=3 cacheSize=3 ****
***** size=4 cacheSize=3 ****
***** size=4 cacheSize=3 ****
==========================================================================
hitCount=0 missCount=0
==========================================================================
null hitCount=0 missCount=1
null hitCount=0 missCount=2
3 hitCount=1 missCount=2
4 hitCount=2 missCount=2
4 hitCount=3 missCount=2
4 hitCount=4 missCount=2
4 hitCount=5 missCount=2
***** size=4 cacheSize=3 ****
***** size=4 cacheSize=3 ****
4 hitCount=6 missCount=2
***** size=4 cacheSize=3 ****
null hitCount=6 missCount=3
==========================================================================
7:7
4:4
8:8
参考文档:
LruCache算法原理及实现的更多相关文章
- Bagging与随机森林算法原理小结
在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系.另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合. ...
- RSA算法原理
一直以来对linux中的ssh认证.SSL.TLS这些安全认证似懂非懂的.看到阮一峰博客中对RSA算法的原理做了非常详细的解释,看完之后茅塞顿开,关于RSA的相关文章如下 RSA算法原理(一) RSA ...
- MySQL索引背后的数据结构及算法原理【转】
本文来自:张洋的MySQL索引背后的数据结构及算法原理 摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持 ...
- OpenGL学习进程(13)第十课:基本图形的底层实现及算法原理
本节介绍OpenGL中绘制直线.圆.椭圆,多边形的算法原理. (1)绘制任意方向(任意斜率)的直线: 1)中点画线法: 中点画线法的算法原理不做介绍,但这里用到最基本的画0<=k ...
- 支持向量机原理(四)SMO算法原理
支持向量机原理(一) 线性支持向量机 支持向量机原理(二) 线性支持向量机的软间隔最大化模型 支持向量机原理(三)线性不可分支持向量机与核函数 支持向量机原理(四)SMO算法原理 支持向量机原理(五) ...
- 分布式缓存技术memcached学习(四)—— 一致性hash算法原理
分布式一致性hash算法简介 当你看到“分布式一致性hash算法”这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么.在分析分布式一致性hash算法原理之前,我们先来了解一下这几 ...
- Logistic回归分类算法原理分析与代码实现
前言 本文将介绍机器学习分类算法中的Logistic回归分类算法并给出伪代码,Python代码实现. (说明:从本文开始,将接触到最优化算法相关的学习.旨在将这些最优化的算法用于训练出一个非线性的函数 ...
- GBDT算法原理深入解析
GBDT算法原理深入解析 标签: 机器学习 集成学习 GBM GBDT XGBoost 梯度提升(Gradient boosting)是一种用于回归.分类和排序任务的机器学习技术,属于Boosting ...
- Atitit 图像清晰度 模糊度 检测 识别 评价算法 原理
Atitit 图像清晰度 模糊度 检测 识别 评价算法 原理 1.1. 图像边缘一般都是通过对图像进行梯度运算来实现的1 1.2. Remark: 1 1.3. 1.失焦检测. 衡量画面模糊的主要方 ...
随机推荐
- 用vue.js学习es6(三):数组、对象和函数的解构
一.数组的解构: 以前的方式: var arr = [1,2,3]; console.log(arr[0]); //1 console.log(arr[1]); //2 现在的方式: var [a,b ...
- SpringMVC注解汇总(一)-定义
本文根据开涛哥学习SpringMVC汇总而成,方便更好查阅! 网址:http://jinnianshilongnian.iteye.com/blog/1752171 注解式控制器简介 @Control ...
- [翻译] V8引擎的解析
原文:Parsing in V8 explained 本文档介绍了 V8 引擎是如何解析 JavaScript 源代码的,以及我们将改进它的计划. 动机 我们有个解析器和一个更快的预解析器(~2x), ...
- jquery.on()超级方法
$.on()方法是jquery1.7之后的一个超级方法,将事件绑定和事件委托整合到一个函数中去,支持绑定多个事件,并且可以绑定自定义事件.使用起来很方便. demo传送门 事件委托 首先说一下事件委托 ...
- 终端指令操作创建Django项目
需求:通过Django创建一个用户表和权限表. 用户表包括:用户名,邮箱,密码,管理权限. 权限表包括:普通用户,管理用户,超级用户. 权限表和用户表有一对多的关系,即用户表中的每条数据对应权限表中的 ...
- 纯JS判断各种浏览器类型及版本.
IE11或者非IE if (!document.all) { alert('IE11+ or not IE'); } IE10 if (document.all && document ...
- POJ1742Coins(并不理解是什么意思)
Coins Time Limit: 3000MS Memory Limit: 30000K Total Submissions: 32309 Accepted: 10986 Descripti ...
- Celery的实践指南
http://www.cnblogs.com/ToDoToTry/p/5453149.html Celery的实践指南 Celery的实践指南 celery原理: celery实际上是实现了一个典 ...
- CSS的常见属性
1. css是cascading style sheet 层叠式样式表的简写."层叠式"的意思,我们将慢慢的去理解. 1 <style type ...
- easyUI 如何不跳转页面,只是加载替换center部分内容
以前做的一个故障报修系统,前端框架使用easyUI框架,layout布局,center使用datagrid .点击左边树形菜单时时页面跳转,想要知道如何点击菜单时不进行页面跳转,而是只对center模 ...