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.失焦检测. 衡量画面模糊的主要方 ...
随机推荐
- .Net mvc 根据前台参数动态绑定对象
业务需求:根据前台界面的参数,动态绑定对象 <param name="colNames">属性名拼接字符串</param><param name=&q ...
- 在 kernel 下打 log。 怪異現象與解決方式。
code battery_log(BAT_LOG_CRTI, "y t: %d \n", (int)my_timer_timeout); battery_log(BAT_LOG_C ...
- canvas-图片翻转
图片90度翻转 在canvas中插入图片需先加载图片(利用Image对象);加载完成后再执行操作drawImage(obj,x,y,w,h) 插入图片的坐标宽高等值 <!DOCTYPE html ...
- from表单提交数组
页面代码: function submitForm(){ var categoryArray = new Array(); var $ss = $("select[name=industry ...
- PRINCE2随笔
首先要说的是,我这篇体会是针对一定的背景的,不能算是一种通用的管理方式,只能是我自己的经验总结,能给大家平常的管理提供一点思路,我就很满足了. 先说说背景,我所在公司做的是大型桌面应用软件,简单点说就 ...
- java+jsp+servlet实现分页
web.xml配置: <servlet> <servlet-name>abc</servlet-name> <servlet-class>test.pa ...
- BFC的布局规则以及触发条件
1 .BFC的含义 : Block Formatting Contexts(BFC) 块级元 ...
- POJ 3204 Ikki's Story I - Road Reconstruction
Ikki's Story I - Road Reconstruction Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 7 ...
- 《Just for Fun》读后感
这本书有一个长长的中文名字:<只是为了好玩:Linux之父林纳斯自传>,所以博客标题我就用英文书名了. 读罢此书,不禁想起一位长者的名言:“一个人的成功当然要靠自我奋斗,但也要考虑历史的进 ...
- js 碎片整理(变量声明,函数作用域)
1.变量声明: 在非严格模式下,函数可以对未声明的变量赋值,而这样赋值的结果就是该变量就会变成全局变量. (function(){ var a = 1; })(); console.log(a) ; ...