Java之理解Redis回收算法LRU案例讲解

如何通俗易懂的理解LRU算法?

1.LRU是什么?

LRU全称Least Recently Used,也就是最近最少使用的意思,是一种内存管理算法,最早应用于Linux操作系统。

LRU算法基于一种假设:长期不被使用的数据,在未来被用到的几率也不大。因此,当数据所占内存达到一定阈值时,我们要移除掉最近最少被使用的数据。

LRU算法应用:可以在内存不够时,从哈希表移除一部分很少访问的用户。

LRU是什么?按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个非常著名的计算机操作系统基础理论得来的:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!因为,利用LRU我们可以解决很多实际开发中的问题,并且很符合业务场景。

2.LRU的需求

首先考虑这样的一个业务场景,小王在A公司上班,有一天产品提出了一个需求:“咱们系统的用户啊,每天活跃的就那么多,有太多的僵尸用户,根本不登录,你能不能考虑做一个筛选机制把这些用户刨出去,并且给活跃的用户做一个排名,我们可以设计出一些奖励活动,提升咱们的用户粘性,咱们只需要关注那些活跃的用户就行了“”。小王连忙点头,说可以啊,然而心里犯起嘀咕来了:这简单,按照常规思路,给用户添加一个最近活跃时间长度和登录次数,然后按照这两个数据计算他们的活跃度,最后直接排序就行了。嘿嘿,简直完美!不过!用户表字段已经很多了,又要加两个字段,然后还得遍历所有的数据排序?这样查询效率是不是会受影响啊?

3.LRU的实现方式

实现 LRUCache 类:

  • LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存;
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

3.1 直接继承LinkedHashMap来实现

public class Code_LRU {
	class LRUCache extends LinkedHashMap<Integer,Integer>{
		private int capacity;
		public LRUCache(int capacity) {
			super(capacity,0.75F,true);
			this.capacity = capacity;
		}

		public int get(int key) {
			return super.getOrDefault(key,-1);
		}
		public void put(int key,int value) {
			super.put(key, value);
		}

		// 重写淘汰策略
		protected boolean removeEldestEntry(Map.Entry<Integer, Integer> edlest) {
			return size()>capacity;
		}
	}
}

3.2 用双向链表+hashMap来实现

// 解题思路:双向链表+hashmap来实现
	class LRUCache_2{
		// 双向链表
		class DLinkedNode{
			int key;
			int value;
			DLinkedNode prev;
			DLinkedNode next;
			public DLinkedNode() {

			}
			public DLinkedNode(int key,int value) {
				this.key = key;
				this.value = value;
			}
		}

		// hashmap
		private HashMap<Integer,DLinkedNode> cache = new HashMap<>();
		// 定义私有变量
		private int size;
		private int capacity;
		private DLinkedNode head,tail;

		public LRUCache_2(int capacity) {
			this.size = 0;
			this.capacity = capacity;
			// 生成伪头部和伪尾部结点
			head = new DLinkedNode();
			tail = new DLinkedNode();
			head.next = tail;
			tail.prev = head;
		}

		//获得值
		public int get(int key) {
			DLinkedNode node = cache.get(key);
			if(node==null) {
				return -1;
			}else {
				// 如果key存在,哈希表定位 结点移动到头部
				moveToHead(node);
				return node.value;
			}
		}

		// 放入值的操作
		public void put(int key,int value) {
			DLinkedNode node = cache.get(key);
			// 如果key不存在
			if(node==null) {
				// 新创建一个结点
				DLinkedNode newNode = new DLinkedNode(key,value);
				// 添加
				cache.put(key,newNode);
				// 添加到头部
				addToHead(newNode);
				++size;
				// 判断容量
				if(size>capacity) {
					// 称号出容量
					DLinkedNode tail = removeTail();
					// 删除hash表中对应的项
					cache.remove(tail.key);
					--size;
				}

			}else {
				node.value = value;
				// 移动
				moveToHead(node);
			}
		}

		// 添加结点的操作
		private void addToHead(DLinkedNode node) {
			node.prev = head;
			node.next = head.next;
			head.next.prev = node;
			head.next = node;
		}

		// 删除结点
		private void removeNode(DLinkedNode node) {
			node.prev.next = node.next;
			node.next.prev = node.prev;
		}

		// 移动到头结点 删结点 填充结点
		private void moveToHead(DLinkedNode node) {
			removeNode(node);
			addToHead(node);
		}
		// 删除尾部结点
		private DLinkedNode removeTail() {
			DLinkedNode res = tail.prev;
			removeNode(res);
			return res;
		}
	}

到此这篇关于Java之理解Redis回收算法LRU案例讲解的文章就介绍到这了,更多相关Java之理解Redis回收算法LRU内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java手动实现Redis的LRU缓存机制

    前言 最近在逛博客的时候看到了有关Redis方面的面试题,其中提到了Redis在内存达到最大限制的时候会使用LRU等淘汰机制,然后找了这方面的一些资料与大家分享一下. LRU总体大概是这样的,最近使用的放在前面,最近没用的放在后面,如果来了一个新的数,此时内存满了,就需要把旧的数淘汰,那为了方便移动数据,肯定就得使用链表类似的数据结构,再加上要判断这条数据是不是最新的或者最旧的那么应该也要使用hashmap等key-value形式的数据结构. 第一种实现(使用LinkedHashMap) pub

  • JAVA实现LRU算法的参考示例

    LRU简介 LRU是Least Recently Used 近期最少使用算法,它就可以将长时间没有被利用的数据进行删除. 实现 最近面了阿里的外包吧,居然也要在线敲代码了,那叫一个紧张啊.题目就是实现一个LRU算法的缓存.外包居然要求也这么高了,哎.还好,LRU是我大学老师布置的一道题目,当然我用C语言实现的,算法原理那是一清二楚,可是面试的时候就脑子一片空白了.好在,边敲代码,边思考,就慢慢想起来了,下面是我的代码.仅供参考 /** * 设计和构建一个"最近最少使用"LRU 缓存,该

  • java LRU算法介绍与用法示例

    本文实例讲述了java LRU算法介绍与用法.分享给大家供大家参考,具体如下: 1.前言 在用户使用联网的软件的时候,总会从网络上获取数据,当在一段时间内要多次使用同一个数据的时候,用户不可能每次用的时候都去联网进行请求,既浪费时间又浪费网络 这时就可以将用户请求过的数据进行保存,但不是任意数据都进行保存,这样会造成内存浪费的.LRU算法的思想就可以运用了. 2.LRU简介 LRU是Least Recently Used 近期最少使用算法,它就可以将长时间没有被利用的数据进行删除. LRU在人们

  • 浅谈Java如何实现一个基于LRU时间复杂度为O(1)的缓存

    LRU:Least Recently Used最近最少使用,当缓存容量不足时,先淘汰最近最少使用的数据.就像JVM垃圾回收一样,希望将存活的对象移动到内存的一端,然后清除其余空间. 缓存基本操作就是读.写.淘汰删除. 读操作时间复杂度为O(1)的那就是hash操作了,可以使用HashMap索引 key. 写操作时间复杂度为O(1),使用链表结构,在链表的一端插入节点,是可以完成O(1)操作,但是为了配合读,还要再次将节点放入HashMap中,put操作最优是O(1),最差是O(n). 不少童鞋就

  • Java实现简单LRU缓存机制的方法

    一.什么是 LRU 算法 就是一种缓存淘汰策略. 计算机的缓存容量有限,如果缓存满了就要删除一些内容,给新内容腾位置.但问题是,删除哪些内容呢?我们肯定希望删掉哪些没什么用的缓存,而把有用的数据继续留在缓存里,方便之后继续使用. LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰. 二.LRU的使用 LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); cache.put(1,

  • 详解Java实现LRU缓存

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

  • 浅谈java如何实现Redis的LRU缓存机制

    目录 LRU概述 使用LinkedHashMap实现 使用LinkedHashMap简单方法实现 双链表+hashmap LRU概述 最近使用的放在前面,最近没用的放在后面,如果来了一个新的数,此时内存满了,就需要把旧的数淘汰,那为了方便移动数据,肯定就得使用链表类似的数据结构,再加上要判断这条数据是不是最新的或者最旧的那么应该也要使用hashmap等key-value形式的数据结构. 使用LinkedHashMap实现 package thread; import java.util.Link

  • Java 手写LRU缓存淘汰算法

    概述 LRU 算法全称为 Least Recently Used 是一种常见的页面缓存淘汰算法,当缓存空间达到达到预设空间的情况下会删除那些最久没有被使用的数据 . 常见的页面缓存淘汰算法主要有一下几种: LRU 最近最久未使用 FIFO 先进先出置换算法 类似队列 OPT 最佳置换算法 (理想中存在的) NRU Clock 置换算法 LFU 最少使用置换算法 PBA 页面缓冲算法 LRU 的原理 LRU 算法的设计原理其实就是计算机的 局部性原理(这个 局部性原理 包含了 空间局部性 和 时间

  • Java之理解Redis回收算法LRU案例讲解

    如何通俗易懂的理解LRU算法? 1.LRU是什么? LRU全称Least Recently Used,也就是最近最少使用的意思,是一种内存管理算法,最早应用于Linux操作系统. LRU算法基于一种假设:长期不被使用的数据,在未来被用到的几率也不大.因此,当数据所占内存达到一定阈值时,我们要移除掉最近最少被使用的数据. LRU算法应用:可以在内存不够时,从哈希表移除一部分很少访问的用户. LRU是什么?按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个非

  • Java之哈夫曼压缩原理案例讲解

    1. 哈夫曼压缩原理 首先要明确一点,计算机里面所有的文件都是以二进制的方式存储的. 在计算机的存储单元中,一个ASCII码值占一个字节,1个字节等于8位(1Byte = 8bit) 可以参考这个网站: ASCII码在线转换计算器 以"JavaJavaJavaJavaJavaJava"这个字符串为例,它在计算机内部是这样存储的(每一个字符的ASCII码转换为二进制存储起来): public static void main(String[] args) { String beforeS

  • Java之ThreadLocal使用常见和方式案例讲解

    目录 1 两大使用场景-ThreadLocal的用途 2 典型场景1:每个线程需要一个独享的对象 3 典型场景2:当前用户信息需要被线程内所有方法共享 4 ThreadLocal方法使用总结 5 ThreadLocal原理 6 ThreadLocal使用问题内存泄露 7 实际应用场景-在spring中的实例分析 [面试高频]- ThreadLocal的使用场景以及使用方式是怎么样的 1 两大使用场景-ThreadLocal的用途 典型场景1:每个线程需要一个独享的对象(通常是工具类,典型需要使用

  • Java之api网关断言及过滤器案例讲解

    目录 一.什么是api网关? 二.常见的api网关 三.使用步骤 1.Spring Cloud Gateway 2.优缺点 3.传统的过滤器 4.使用gateway 4.1module 4.2添加pom依赖 4.3yaml配置 4.4主程序开启注解@EnableDiscoveryClient 四.执行流程 五.断言 5.1: 自定义断言 5.2: 过滤器 一.什么是api网关? 所谓的API网关,就是指后台系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一 路由服务,一些与业务本身功能

  • Java之mybatis使用limit实现分页案例讲解

    1. Limit实现分页 1.1 为什么需要分页 减少数据的处理量 1.2 使用Limit实现分页 select * from user limit startIndex,pageSize; # 注意是从startIndex+1开始查询 pageSize 个 select * from user limit 3; # [0,3] 1.3 使用mybatis实现分页(核心:SQL) 1.3.1 接口 UserMapper.java // limit实现分页 Map后面只能是 Integer 包装类

  • php之redis短线重连案例讲解

    php redis断线重连,pconnect连接失败问题 介绍 在swoole ,workerman等cli长连接模式下,遇到Redis异常断开,后面又开启的情况,一般得重新启动程序才能正常使用, 本文介绍在不重启服务,实现原来的Redis断线重连 原理 Redis 断开的情况下调用 $Redis->ping()会触发Notice错误,Notice: Redis::ping(): send of 14 bytes failed with errno=10054 当获取redis实例时,如果pin

  • Java之实现十进制与十六进制转换案例讲解

    写了两种十六进制转十进制的方式,仅供参考. 基本思路:用十六进制中每一位数乘以对应的权值,再求和就是对应的十进制 方法一: import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class Test { /** * @param: [content] * @return: int * @description: 十六进制转十进制 */ public static int covert(St

  • Java之Springcloud Gateway内置路由案例讲解

    Spring Cloud Gateway路由匹配是Spring WebFlux基础功能的一部分,在Spring Cloud Gateway中内置了很多路由断言工厂类.不同的断言工厂类针对HTTP请求的不同属性.多个断言工厂类可以使用逻辑"and"进行组合使用. 4.1 After Route Predicate Factory        这个Predicate工厂的实现类是AfterRoutePredicateFactory,使用一个时间参数,如果当前请求的时间在配置的赶时间之后,

  • Java数据结构 递归之迷宫回溯案例讲解

    问题介绍: 用二维数组表示一个迷宫,设置迷宫起点和终点,输出迷宫中的一条通路 实现思路: 二维数组表示迷宫: 0表示路且未走过.1表示墙.2表示通路,3表示已经走过但走不通 设置寻路方法setWay,传入地图和坐标参数 默认方向策略:下.右.上.左 假定传入的店没有走过且可以走通,将其值置为2,然后向下寻路,也就是将坐标 (i + 1, j) 传入寻路方法中 进行递归寻路,向下移动后,再次按照方向策略进行寻路,即再向下寻路,直到遇到死路,即下右左均走不通(因为将走过的路置为2,故向上也走不通,即

  • 深入理解JVM垃圾回收算法

    目录 一.垃圾标记阶段 1.1.引用计数法 (java没有采用) 1.2.可达性分析算法 二.对象的finalization机制 2.1.对象是否"死亡" 三.使用(MAT与JProfiler)工具分析GCRoots 3.1.获取dump文件 3.2.GC Roots分析 四.垃圾清除阶段 4.1.标记-清除算法 4.2.复制算法 4.3.标记-压缩(整理,Mark-Compact)算法 4.4.以上三种垃圾回收算法对比 4.5.分代收集算法 4.6.增量收集算法 4.7.分区算法G1

随机推荐