LRU是Least Recently Used 的缩写,翻译过来就是“最近最少使用”,LRU缓存就是使用这种原理实现,简单的说就是缓存一定量的数据,当超过设定的阈值时就把一些过期的数据删除掉,比如我们缓存10000条数据,当数据小于10000时可以随意添加,当超过10000时就需要把新的数据添加进来,同时要把过期数据删除,以确保我们最大缓存10000条,那怎么确定删除哪条过期数据呢,采用LRU算法实现的话就是将最老的数据删掉,废话不多说,下面来说下Java版的LRU缓存实现

Java里面实现LRU缓存通常有两种选择,一种是使用LinkedHashMap,一种是自己设计数据结构,使用链表+HashMap

LRU Cache的LinkedHashMap实现

LinkedHashMap自身已经实现了顺序存储,默认情况下是按照元素的添加顺序存储,也可以启用按照访问顺序存储,即最近读取的数据放在最前面,最早读取的数据放在最后面,然后它还有一个判断是否删除最老数据的方法,默认是返回false,即不删除数据,我们使用LinkedHashMap实现LRU缓存的方法就是对LinkedHashMap实现简单的扩展,扩展方式有两种,一种是inheritance,一种是delegation,具体使用什么方式看个人喜好

//LinkedHashMap的一个构造函数,当参数accessOrder为true时,即会按照访问顺序排序,最近访问的放在最前,最早访问的放在后面
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {super(initialCapacity, loadFactor);this.accessOrder = accessOrder;
}//LinkedHashMap自带的判断是否删除最老的元素方法,默认返回false,即不删除老数据
//我们要做的就是重写这个方法,当满足一定条件时删除老数据
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {return false;
}

LRU缓存LinkedHashMap(inheritance)实现

采用inheritance方式实现比较简单,而且实现了Map接口,在多线程环境使用时可以使用 Collections.synchronizedMap()方法实现线程安全操作

package cn.lzrabbit.structure.lru;import java.util.LinkedHashMap;
import java.util.Map;/*** Created by liuzhao on 14-5-15.*/
public class LRUCache2<K, V> extends LinkedHashMap<K, V> {private final int MAX_CACHE_SIZE;public LRUCache2(int cacheSize) {super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);MAX_CACHE_SIZE = cacheSize;}@Overrideprotected boolean removeEldestEntry(Map.Entry eldest) {return size() > MAX_CACHE_SIZE;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();for (Map.Entry<K, V> entry : entrySet()) {sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));}return sb.toString();}
}

这样算是比较标准的实现吧,实际使用中这样写还是有些繁琐,更实用的方法时像下面这样写,省去了单独见一个类的麻烦

final int cacheSize = 100;
Map<String, String> map = new LinkedHashMap<String, String>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {@Overrideprotected boolean removeEldestEntry(Map.Entry<String, String> eldest) {return size() > cacheSize;}
};

LRU缓存LinkedHashMap(delegation)实现

delegation方式实现更加优雅一些,但是由于没有实现Map接口,所以线程同步就需要自己搞定了

package cn.lzrabbit.structure.lru;import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;/*** Created by liuzhao on 14-5-13.*/
public class LRUCache3<K, V> {private final int MAX_CACHE_SIZE;private final float DEFAULT_LOAD_FACTOR = 0.75f;LinkedHashMap<K, V> map;public LRUCache3(int cacheSize) {MAX_CACHE_SIZE = cacheSize;//根据cacheSize和加载因子计算hashmap的capactiy,+1确保当达到cacheSize上限时不会触发hashmap的扩容,int capacity = (int) Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTOR) + 1;map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTOR, true) {@Overrideprotected boolean removeEldestEntry(Map.Entry eldest) {return size() > MAX_CACHE_SIZE;}};}public synchronized void put(K key, V value) {map.put(key, value);}public synchronized V get(K key) {return map.get(key);}public synchronized void remove(K key) {map.remove(key);}public synchronized Set<Map.Entry<K, V>> getAll() {return map.entrySet();}public synchronized int size() {return map.size();}public synchronized void clear() {map.clear();}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();for (Map.Entry entry : map.entrySet()) {sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));}return sb.toString();}
}

LRU Cache的链表+HashMap实现

注:此实现为非线程安全,若在多线程环境下使用需要在相关方法上添加synchronized以实现线程安全操作

package cn.lzrabbit.structure.lru;import java.util.HashMap;/*** Created by liuzhao on 14-5-12.*/
public class LRUCache1<K, V> {private final int MAX_CACHE_SIZE;private Entry first;private Entry last;private HashMap<K, Entry<K, V>> hashMap;public LRUCache1(int cacheSize) {MAX_CACHE_SIZE = cacheSize;hashMap = new HashMap<K, Entry<K, V>>();}public void put(K key, V value) {Entry entry = getEntry(key);if (entry == null) {if (hashMap.size() >= MAX_CACHE_SIZE) {hashMap.remove(last.key);removeLast();}entry = new Entry();entry.key = key;}entry.value = value;moveToFirst(entry);hashMap.put(key, entry);}public V get(K key) {Entry<K, V> entry = getEntry(key);if (entry == null) return null;moveToFirst(entry);return entry.value;}public void remove(K key) {Entry entry = getEntry(key);if (entry != null) {if (entry.pre != null) entry.pre.next = entry.next;if (entry.next != null) entry.next.pre = entry.pre;if (entry == first) first = entry.next;if (entry == last) last = entry.pre;}hashMap.remove(key);}private void moveToFirst(Entry entry) {if (entry == first) return;if (entry.pre != null) entry.pre.next = entry.next;if (entry.next != null) entry.next.pre = entry.pre;if (entry == last) last = last.pre;if (first == null || last == null) {first = last = entry;return;}entry.next = first;first.pre = entry;first = entry;entry.pre = null;}private void removeLast() {if (last != null) {last = last.pre;if (last == null) first = null;else last.next = null;}}private Entry<K, V> getEntry(K key) {return hashMap.get(key);}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();Entry entry = first;while (entry != null) {sb.append(String.format("%s:%s ", entry.key, entry.value));entry = entry.next;}return sb.toString();}class Entry<K, V> {public Entry pre;public Entry next;public K key;public V value;}
}

LinkedHashMap的FIFO实现

FIFO是First Input First Output的缩写,也就是常说的先入先出,默认情况下LinkedHashMap就是按照添加顺序保存,我们只需重写下removeEldestEntry方法即可轻松实现一个FIFO缓存,简化版的实现代码如下

final int cacheSize = 5;
LinkedHashMap<Integer, String> lru = new LinkedHashMap<Integer, String>() {@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) {return size() > cacheSize;}
};

调用示例

测试代码

 View Code

运行结果

 View Code

LRU缓存实现(Java)相关推荐

  1. 算法---Lru缓存(Java)

    题目: 设计和构建一个"最近最少使用"缓存,该缓存会删除最近最少使用的项目.缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量.当缓存被填满时,它应该 ...

  2. 10 行 Java 代码实现 LRU 缓存

    10 行 Java 代码实现 LRU 缓存 (整理自网络) 最近最少使用缓存的回收 为了实现缓存回收,我们需要很容易做到: 查询出最近最晚使用的项 给最近最少使用的项做一个标记 链表可以实现这两个操作 ...

  3. java mysql lru_Java集合详解5:深入理解LinkedHashMap和LRU缓存

    今天我们来深入探索一下LinkedHashMap的底层原理,并且使用linkedhashmap来实现LRU缓存. 摘要:HashMap和双向链表合二为一即是LinkedHashMap.所谓Linked ...

  4. java实现lru缓存_Java中的LRU缓存实现

    java实现lru缓存 什么是LRU缓存? (What is LRU Cache?) LRU Cache stands for Least Recently Used Cache. The size ...

  5. Java集合详解5:深入理解LinkedHashMap和LRU缓存

    <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...

  6. Java实现 LeetCode 146 LRU缓存机制

    146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...

  7. 看动画轻松理解「链表」实现「LRU缓存淘汰算法」

    作者 | 程序员小吴,哈工大学渣,目前正在学算法,开源项目 「 LeetCodeAnimation 」5500star,GitHub Trending 榜连续一月第一. 本文为 AI科技大本营投稿文章 ...

  8. 常考数据结构和算法:设计LRU缓存结构

    题目描述 设计LRU缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能 set(key, value):将记录(key, value)插入该结构 get(key):返回key对应的val ...

  9. 实现 LRU 缓存机制

    实现 LRU 缓存机制 文章目录 实现 LRU 缓存机制 一.什么是 LRU 算法 二.LRU 算法描述 三.LRU 算法设计 四.代码实现 一.什么是 LRU 算法 LRU 就是一种缓存淘汰策略.( ...

最新文章

  1. 为什么要研究游戏 AI 呢?
  2. python 批量处理文件重命名
  3. HDFS组件性能调优:数据平衡
  4. 网站SEO优化如何讨好搜索引擎蜘蛛?
  5. 任意1-10中的4个数字,使用加减乘除计算得出24结果的可能组合(java版),很多人小时候都玩过...
  6. 趣味编程:C#中Specification模式的实现
  7. linux exit 源码,Linux命令——exit、sulogin、rlogin
  8. BlogEngine.Net架构与源代码分析系列索引贴
  9. 【python】py课上机作业3「谢尔宾斯基三角形」「递归输出列表」
  10. python清除历史记录_只需python两行代码,就能获取你的浏览器历史浏览记录
  11. 【Excel】Excel条件格式设置背景色
  12. 使用python3+pyqt5实现图片识别文字工具
  13. PythonOperator、BashOperator以及Xcom使用
  14. ST-GAN: Spatial Transformer Generative Adversarial Networks for Image Compositing 原文翻译
  15. 幼儿园小班计算机教案,幼儿园小班安全教案7篇
  16. 一个SAPer的网络日志-连载四-三不主义下的项目经理
  17. 第一讲 VMware 软件安装和虚拟机创建
  18. matlab-画一个圆
  19. DoS/DDoS的现状分析和典型案例
  20. SSOJ 2316 面积【DFS/Flood Fill】

热门文章

  1. shell脚本详解(十二)——Here Document免交互及Expect自动化交互
  2. excluded by a filter_A. Manthiram:碲入硫,锂更稳!
  3. 俄亥俄州立大学计算机专业排名,美国俄亥俄州立大学各专业的排名情况介绍
  4. android.process.media+sd,android P系统WRITE_MEDIA_STORAGE添加读写SD卡权限
  5. @override报错_C++ 多态性:C++11:override 与 final(学习笔记:第8章 09)
  6. spring图片转视频_一直在用的 Spring,你知道它的加载原理吗?
  7. android opencv 识别文字_基于SpringBoot的车牌识别系统(附项目地址)
  8. c语言标准输入输出ppt,c语言输入输出语句PPT
  9. 端口映射工具linux,Linux下端口映射工具rinetd(示例代码)
  10. python中打印所有的关键字_python 查看所有的关键字