服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java之理解Redis回收算法LRU案例讲解

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

2021-11-11 10:45mind_programmonkey Java教程

这篇文章主要介绍了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来实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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来实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// 解题思路:双向链表+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内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://codingchaozhang.blog.csdn.net/article/details/114272429

延伸 · 阅读

精彩推荐
  • Java教程20个非常实用的Java程序代码片段

    20个非常实用的Java程序代码片段

    这篇文章主要为大家分享了20个非常实用的Java程序片段,对java开发项目有所帮助,感兴趣的小伙伴们可以参考一下 ...

    lijiao5352020-04-06
  • Java教程Java实现抢红包功能

    Java实现抢红包功能

    这篇文章主要为大家详细介绍了Java实现抢红包功能,采用多线程模拟多人同时抢红包,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙...

    littleschemer13532021-05-16
  • Java教程xml与Java对象的转换详解

    xml与Java对象的转换详解

    这篇文章主要介绍了xml与Java对象的转换详解的相关资料,需要的朋友可以参考下...

    Java教程网2942020-09-17
  • Java教程升级IDEA后Lombok不能使用的解决方法

    升级IDEA后Lombok不能使用的解决方法

    最近看到提示IDEA提示升级,寻思已经有好久没有升过级了。升级完毕重启之后,突然发现好多错误,本文就来介绍一下如何解决,感兴趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java BufferWriter写文件写不进去或缺失数据的解决

    Java BufferWriter写文件写不进去或缺失数据的解决

    这篇文章主要介绍了Java BufferWriter写文件写不进去或缺失数据的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java8中Stream使用的一个注意事项

    Java8中Stream使用的一个注意事项

    最近在工作中发现了对于集合操作转换的神器,java8新特性 stream,但在使用中遇到了一个非常重要的注意点,所以这篇文章主要给大家介绍了关于Java8中S...

    阿杜7482021-02-04
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    这篇文章主要介绍了Java使用SAX解析xml的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程小米推送Java代码

    小米推送Java代码

    今天小编就为大家分享一篇关于小米推送Java代码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    富贵稳中求8032021-07-12