GuavaCache学习笔记一:自定义LRU算法的缓存实现
时间:2022-06-16
本文章向大家介绍GuavaCache学习笔记一:自定义LRU算法的缓存实现,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
前言
今天在看GuavaCache缓存相关的源码,这里想到先自己手动实现一个LRU算法。于是乎便想到LinkedHashMap和LinkedList+HashMap, 这里仅仅是作为简单的复习一下。
LRU
LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
代码实现原理
LinkedList + HashMap: LinkedList其实是一个双向链表,我们可以通过get和put来设置最近请求key的位置,然后hashMap去存储数据 LinkedHashMap:LinkedHashMap是继承自HashMap,只不过Map中的Node节点改为了双向节点,双向节点可以维护添加的顺序,在LinkedHashMap的构造函数中有一个accessOrder, 当设置为true后,put和get会自动维护最近请求的位置到last。
LinkedList+HashMap代码实现
LRUCache接口:
/**
* @Description:
* @Author: wangmeng
* @Date: 2018/12/8-10:49
*/
public class LinkedListLRUTest {
public static void main(String[] args) {
LRUCache<String, String> cache = new LinkedListLRUCache<>(3);
cache.put("1", "1");
cache.put("2", "2");
cache.put("3", "3");
System.out.println(cache);
cache.put("4", "4");
System.out.println(cache);
System.out.println(cache.get("2"));
System.out.println(cache);
}
}
LinkedList实现:
/**
* @Description:使用LinkedList+HashMap来实现LRU算法
* @Author: wangmeng
* @Date: 2018/12/8-10:41
*/
public class LinkedListLRUCache<K, V> implements LRUCache<K, V> {
private final int limit;
private final LinkedList<K> keys = new LinkedList<>();
private final Map<K, V> cache = Maps.newHashMap();
public LinkedListLRUCache(int limit) {
this.limit = limit;
}
@Override
public void put(K key, V value) {
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(value);
if (keys.size() >= limit) {
K oldesKey = keys.removeFirst();
cache.remove(oldesKey);
}
keys.addLast(key);
cache.put(key, value);
}
@Override
public V get(K key) {
boolean exist = keys.remove(key);
if (!exist) {
return null;
}
keys.addLast(key);
return cache.get(key);
}
@Override
public void remove(K key) {
boolean exist = keys.remove(key);
if (exist) {
keys.remove(key);
cache.remove(key);
}
}
@Override
public int size() {
return keys.size();
}
@Override
public void clear() {
keys.clear();
cache.clear();
}
@Override
public int limit() {
return this.limit;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (K key : keys) {
builder.append(key).append("=").append(cache.get(key)).append(";");
}
return builder.toString();
}
}
LinkedList测试类:
/**
* @Description:
* @Author: wangmeng
* @Date: 2018/12/8-10:49
*/
public class LinkedListLRUTest {
public static void main(String[] args) {
LRUCache<String, String> cache = new LinkedListLRUCache<>(3);
cache.put("1", "1");
cache.put("2", "2");
cache.put("3", "3");
System.out.println(cache);
cache.put("4", "4");
System.out.println(cache);
System.out.println(cache.get("2"));
System.out.println(cache);
}
}
LinkedList测试类返回值:
1=1;2=2;3=3;
2=2;3=3;4=4;
2
3=3;4=4;2=2;
LinkedHashMap实现
/**
* @Description: 不是一个线程安全的类,这里是使用LinkedHashMap来做LRU算法
* @Author: wangmeng
* @Date: 2018/12/8-10:14
*/
public class LinkedHashLRUCache<K, V> implements LRUCache<K, V> {
private static class InternalLRUCache<K, V> extends LinkedHashMap<K, V> {
final private int limit;
private InternalLRUCache(int limit) {
super(16, 0.75f, true);
this.limit = limit ;
}
//实现remove元素的方法,这个是重写了LinkedHashMap中的方法。因为在HashMap的putVal会调用afterNodeInsertion(), 而这个方法会判断removeEldestEntry方法。
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > limit;
}
}
private final int limit;
//使用组合关系优于继承,这里只对外暴漏LRUCache中的方法
private final InternalLRUCache<K, V> internalLRUCache;
public LinkedHashLRUCache(int limit) {
Preconditions.checkArgument(limit > 0, "The limit big than zero.");
this.limit = limit;
this.internalLRUCache = new InternalLRUCache(limit);
}
@Override
public void put(K key, V value) {
this.internalLRUCache.put(key, value);
}
@Override
public V get(K key) {
return this.internalLRUCache.get(key);
}
@Override
public void remove(K key) {
this.internalLRUCache.remove(key);
}
@Override
public int size() {
return this.internalLRUCache.size();
}
@Override
public void clear() {
this.internalLRUCache.clear();
}
@Override
public int limit() {
return this.limit;
}
@Override
public String toString() {
return internalLRUCache.toString();
}
}
LinkedHashMap测试类:
/**
* @Description:
* @Author: wangmeng
* @Date: 2018/12/8-10:30
*/
public class LinkedHashLRUTest {
public static void main(String[] args) {
LRUCache<String, String> cache = new LinkedHashLRUCache<>(3);
cache.put("1", "1");
cache.put("2", "2");
cache.put("3", "3");
System.out.println(cache);
cache.put("4", "4");
System.out.println(cache);
System.out.println(cache.get("2"));
System.out.println(cache);
}
}
LinkedHashMap测试结果:
{1=1, 2=2, 3=3}
{2=2, 3=3, 4=4}
2
{3=3, 4=4, 2=2}
- MySQL事务autocommit自动提交
- wcf webHttpBinding Post 大数据量提交 ios c#客户端
- 你现在还在手动生成set,get方法吗?
- ios 接收 c# socket udp 组播
- 大数据基础系列之JAVA引用详解
- Java集合深度解析之ArrayList
- wpf listBox 多列大图片效果
- ASP.NET 主题(Themes)FAQ
- wpf 解决 编码解码器无法使用提供的流类型 The codec cannot use the type of stream provided
- Java 9 逆天的十大新特性
- 设计模式:命令模式
- mysql的外键
- 设计模式:工厂方法模式
- 设计模式:抽象工厂方法模式
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux内存泄漏检测shell脚本
- 详解Linux系统中网卡MAC地址克隆方法
- linux下日志定时轮询的流程详解
- Vim中查找替换及正则表达式的使用详解
- CentOS 7下部署php7.1和开启MySQL扩展的方法教程
- Ubuntu系统下用Crontab命令定时执行PHP文件详解
- CentOS7 LNMP+phpmyadmin环境搭建 第三篇phpmyadmin安装
- Linux有限状态机FSM的理解与实现
- Linux下浅谈crond与crontab的命令用法
- centos 7系统下安装Jenkins的步骤详解
- linux tomcat配置https的方法
- Linux 中firewall的使用方法总结
- CentOS 7 安装vsftpd 服务器的具体操作步骤
- 详细介绍通过配置Apache实现404页面替换
- bug分支和feature分支_动力节点Java学院整理