前言

今天在看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}

GuavaCache学习笔记一:自定义LRU算法的缓存实现的更多相关文章

  1. [转载]SharePoint 2013搜索学习笔记之自定义结果源

    搜索中心新建好之后在搜索结果页上会默认有所有内容,人员,对话,视频这四个结果分类,每个分类会返回指定范围的搜索结果,这里我再添加了部门日志结果分类,搜索这个分类只会返回部门日志内容类型的搜索结果,要实 ...

  2. Hadoop学习笔记—5.自定义类型处理手机上网日志

    转载自http://www.cnblogs.com/edisonchou/p/4288737.html Hadoop学习笔记—5.自定义类型处理手机上网日志 一.测试数据:手机上网日志 1.1 关于这 ...

  3. 机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集

    机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集 关键字:FPgrowth.频繁项集.条件FP树.非监督学习作者:米 ...

  4. 机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析

    机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析 关键字:Apriori.关联规则挖掘.频繁项集作者:米仓山下时间:2018 ...

  5. 机器学习实战(Machine Learning in Action)学习笔记————02.k-邻近算法(KNN)

    机器学习实战(Machine Learning in Action)学习笔记————02.k-邻近算法(KNN) 关键字:邻近算法(kNN: k Nearest Neighbors).python.源 ...

  6. [ML学习笔记] 朴素贝叶斯算法(Naive Bayesian)

    [ML学习笔记] 朴素贝叶斯算法(Naive Bayesian) 贝叶斯公式 \[P(A\mid B) = \frac{P(B\mid A)P(A)}{P(B)}\] 我们把P(A)称为"先 ...

  7. Effective STL 学习笔记 31:排序算法

    Effective STL 学习笔记 31:排序算法 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...

  8. shiro学习笔记_0600_自定义realm实现授权

    博客shiro学习笔记_0400_自定义Realm实现身份认证 介绍了认证,这里介绍授权. 1,仅仅通过配置文件来指定权限不够灵活且不方便.在实际的应用中大多数情况下都是将用户信息,角色信息,权限信息 ...

  9. ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则

    ASP.NET MVC 学习笔记-7.自定义配置信息   ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...

随机推荐

  1. Codeforces 514E Darth Vader and Tree 矩阵快速幂

    Darth Vader and Tree 感觉是个很裸的矩阵快速幂, 搞个100 × 100 的矩阵, 直接转移就好啦. #include<bits/stdc++.h> #define L ...

  2. Python打包方法——Pyinstaller (转)

      Python版本:Python3.5.2 一.安装Pyinstaller 1.安装pywin32 下载安装文件:查找到跟自己适用的python版本及window系统版本匹配的pywin32,下载后 ...

  3. scanf清除缓存区

    为什么需要清除scanf缓存区呢?看一个例子: int main() { int a,b; scanf("%d",&a); scanf("%d",&am ...

  4. 基于 Jenkins+Docker+Git 的CI流程初探

    在如今的互联网时代,随着软件开发复杂度的不断提高,软件开发和发布管理也越来越重要.目前已经形成一套标准的流程,最重要的组成部分就是持续集成(Continuous Integration,CI)及持续部 ...

  5. Node.js之图片上传

    本文用node进行图片上传主要借助formidable插件,具体使用步骤如下: 1.安装formidable插件 npm install formidable -g 2.引入依赖包 const for ...

  6. 三篇文章带你极速入门php(二)之迅速搭建php环境

    前言 今天讲一下php在windows,mac,linux上的集成环境搭建,目标是简单快速,环境这个事得对号入座,windows用phpstudy,mac用mamp,linux用lnmp一键安装,直接 ...

  7. ubuntu安装mysql 时未提示输入密码

    我在Ubuntu16.04版本中使用终端安装MySQL5.7时,按照度娘的教程,搜索如何安装,大多是如下代码: sudo apt-get install mysql-server sudo apt-g ...

  8. Codeforces.600E.Lomsat gelral(dsu on tree)

    题目链接 dsu on tree详见这. \(Description\) 给定一棵树.求以每个点为根的子树中,出现次数最多的颜色的和. \(Solution\) dsu on tree模板题. 用\( ...

  9. [CC-LONCYC]Lonely Cycles

    [CC-LONCYC]Lonely Cycles 题目大意: \(T(T\le1000)\)组数据. 给定一张简单图(不含重边与自环),图中有\(n(n\le2\times10^5)\)个节点和\(m ...

  10. VC6配置CXimage库

    VC6下配置CxImage库教程 第一步 下载CxImage http://sourceforge.net/projects/cximage/下载相应的CxImage文件 本例使用的最新版本(7.02 ...