LruCache算法原理及实现

LruCache算法原理

LRULeast Recently Used的缩写,意思也就是近期最少使用算法。LruCacheLinkedHashMap的顺序设置为LRU顺序来实现LRU缓存,每次调用get并获取到值(也就是从内存缓存中命中),则将该对象移到链表的尾端。调用put插入新的对象也是存储在链表尾端,这样当内存缓存达到设定的最大值时,将链表头部的对象(近期最少用到的)移除。

基于LinkedHashMapLRUCache的实现,关键是重写LinkedHashMapremoveEldestEntry方法,在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算法原理及实现的更多相关文章

  1. Bagging与随机森林算法原理小结

    在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系.另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合. ...

  2. RSA算法原理

    一直以来对linux中的ssh认证.SSL.TLS这些安全认证似懂非懂的.看到阮一峰博客中对RSA算法的原理做了非常详细的解释,看完之后茅塞顿开,关于RSA的相关文章如下 RSA算法原理(一) RSA ...

  3. MySQL索引背后的数据结构及算法原理【转】

    本文来自:张洋的MySQL索引背后的数据结构及算法原理 摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持 ...

  4. OpenGL学习进程(13)第十课:基本图形的底层实现及算法原理

        本节介绍OpenGL中绘制直线.圆.椭圆,多边形的算法原理.     (1)绘制任意方向(任意斜率)的直线: 1)中点画线法: 中点画线法的算法原理不做介绍,但这里用到最基本的画0<=k ...

  5. 支持向量机原理(四)SMO算法原理

    支持向量机原理(一) 线性支持向量机 支持向量机原理(二) 线性支持向量机的软间隔最大化模型 支持向量机原理(三)线性不可分支持向量机与核函数 支持向量机原理(四)SMO算法原理 支持向量机原理(五) ...

  6. 分布式缓存技术memcached学习(四)—— 一致性hash算法原理

    分布式一致性hash算法简介 当你看到“分布式一致性hash算法”这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么.在分析分布式一致性hash算法原理之前,我们先来了解一下这几 ...

  7. Logistic回归分类算法原理分析与代码实现

    前言 本文将介绍机器学习分类算法中的Logistic回归分类算法并给出伪代码,Python代码实现. (说明:从本文开始,将接触到最优化算法相关的学习.旨在将这些最优化的算法用于训练出一个非线性的函数 ...

  8. GBDT算法原理深入解析

    GBDT算法原理深入解析 标签: 机器学习 集成学习 GBM GBDT XGBoost 梯度提升(Gradient boosting)是一种用于回归.分类和排序任务的机器学习技术,属于Boosting ...

  9. Atitit 图像清晰度 模糊度 检测 识别 评价算法 原理

    Atitit 图像清晰度 模糊度 检测 识别 评价算法 原理 1.1. 图像边缘一般都是通过对图像进行梯度运算来实现的1 1.2. Remark: 1 1.3.  1.失焦检测. 衡量画面模糊的主要方 ...

随机推荐

  1. .Net mvc 根据前台参数动态绑定对象

    业务需求:根据前台界面的参数,动态绑定对象 <param name="colNames">属性名拼接字符串</param><param name=&q ...

  2. 在 kernel 下打 log。 怪異現象與解決方式。

    code battery_log(BAT_LOG_CRTI, "y t: %d \n", (int)my_timer_timeout); battery_log(BAT_LOG_C ...

  3. canvas-图片翻转

    图片90度翻转 在canvas中插入图片需先加载图片(利用Image对象);加载完成后再执行操作drawImage(obj,x,y,w,h) 插入图片的坐标宽高等值 <!DOCTYPE html ...

  4. from表单提交数组

    页面代码: function submitForm(){ var categoryArray = new Array(); var $ss = $("select[name=industry ...

  5. PRINCE2随笔

    首先要说的是,我这篇体会是针对一定的背景的,不能算是一种通用的管理方式,只能是我自己的经验总结,能给大家平常的管理提供一点思路,我就很满足了. 先说说背景,我所在公司做的是大型桌面应用软件,简单点说就 ...

  6. java+jsp+servlet实现分页

    web.xml配置: <servlet> <servlet-name>abc</servlet-name> <servlet-class>test.pa ...

  7. BFC的布局规则以及触发条件

          1   .BFC的含义 :          Block Formatting Contexts(BFC)                                      块级元 ...

  8. POJ 3204 Ikki's Story I - Road Reconstruction

    Ikki's Story I - Road Reconstruction Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 7 ...

  9. 《Just for Fun》读后感

    这本书有一个长长的中文名字:<只是为了好玩:Linux之父林纳斯自传>,所以博客标题我就用英文书名了. 读罢此书,不禁想起一位长者的名言:“一个人的成功当然要靠自我奋斗,但也要考虑历史的进 ...

  10. js 碎片整理(变量声明,函数作用域)

    1.变量声明: 在非严格模式下,函数可以对未声明的变量赋值,而这样赋值的结果就是该变量就会变成全局变量. (function(){ var a = 1; })(); console.log(a) ; ...