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

时间:2022-08-26 09:05:28

LRU概述

最近使用的放在前面,最近没用的放在后面,如果来了一个新的数,此时内存满了,就需要把旧的数淘汰,那为了方便移动数据,肯定就得使用链表类似的数据结构,再加上要判断这条数据是不是最新的或者最旧的那么应该也要使用hashmap等key-value形式的数据结构。

使用LinkedHashMap实现

  1. package thread;
  2. import java.util.LinkedHashMap;
  3. import java.util.Map;
  4.  
  5. public class LRUCacheTest {
  6. int capacity;
  7. Map<Integer,Integer> map;
  8.  
  9. public LRUCacheTest(int capacity){
  10. this.capacity = capacity;
  11. map = new LinkedHashMap<>();
  12. }
  13.  
  14. public int get(int key){
  15. //没有找到
  16. if(!map.containsKey(key)){
  17. return -1;
  18. }
  19. Integer value = map.remove(key);
  20. map.put(key,value);
  21. return value;
  22. }
  23.  
  24. public void put(int key,int value){
  25. if(map.containsKey(key)){
  26. map.remove(key);
  27. map.put(key,value);
  28. return;
  29. }
  30. map.put(key,value);
  31. //超出capacity,删除最久没用的即第一个,或者可以复写removeEldestEntry方法
  32. if(map.size() > capacity){
  33. map.remove(map.entrySet().iterator().next().getKey());
  34. }
  35.  
  36. }
  37.  
  38. public static void main(String[] args) {
  39. LRUCacheTest lruCache = new LRUCacheTest(10);
  40. for (int i = 0; i < 10; i++) {
  41. lruCache.map.put(i,i);
  42. System.out.print(lruCache.map.size()+"\t");
  43. }
  44. System.out.println();
  45. System.out.println(lruCache.map);
  46. lruCache.put(10,200);
  47. System.out.println(lruCache.map);
  48. lruCache.put(11,100);
  49. System.out.println(lruCache.map);
  50. lruCache.get(2);
  51. System.out.println(lruCache.map);
  52. }
  53.  
  54. }

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

结果来看是正确的,距离当前时间最远的数据被淘汰

使用LinkedHashMap简单方法实现

LinkedHashMap是维护了双向链表的HashMap,保持了插入元素的顺序。

LinkedHashMap提供了一个钩子方法,在新插入元素后可以决定是否删除最老的元素。

复写removeEldestEntry实现

  1. package thread;
  2. import java.util.LinkedHashMap;
  3. import java.util.Map;
  4.  
  5. public class LRUByLinkedHashMap extends LinkedHashMap<Integer,Integer> {
  6. /**
  7. * LRU中最大元素数量
  8. */
  9. private int maxSize;
  10.  
  11. public LRUByLinkedHashMap(int maxSize) {
  12. // 容量为最大值/0.75,即最大负载容量为maxSize
  13. // accessOrder=true 根据查询排序,即最近被使用的放到后面
  14. super((int) Math.ceil(maxSize / 0.75) + 1, 0.75f, true);
  15. this.maxSize = maxSize;
  16. }
  17.  
  18. /**
  19. * 此方法为钩子方法,map插入元素时会调用此方法
  20. * 此方法返回true则证明删除最老的因子
  21. * @param eldest
  22. * @return
  23. */
  24. @Override
  25. protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
  26. return size() > maxSize;
  27. }
  28.  
  29. public static void main(String[] args) {
  30. LRUByLinkedHashMap hashMap = new LRUByLinkedHashMap(10);
  31. for (int i = 0; i < 10; i++) {
  32. hashMap.put(i,i);
  33. System.out.print(hashMap.size()+"\t");
  34. }
  35. System.out.println();
  36. System.out.println(hashMap);
  37. hashMap.put(10,200);
  38. System.out.println(hashMap);
  39. hashMap.put(11,100);
  40. System.out.println(hashMap);
  41. hashMap.get(10);
  42. System.out.println(hashMap);
  43. }
  44.  
  45. }

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

双链表+hashmap

  1. package thread;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4.  
  5. public class LRURedis {
  6. private int capacity;
  7. private Map<Integer,ListNode> map;
  8. private ListNode head;
  9. private ListNode tail;
  10.  
  11. public LRURedis(int capacity){
  12. this.capacity = capacity;
  13. map = new HashMap<>();
  14. head = new ListNode(-1,-1);
  15. tail = new ListNode(-1,-1);
  16. head.next = tail;
  17. tail.pre = head;
  18. }
  19.  
  20. public int get(int key){
  21. if(!map.containsKey(key)){
  22. return -1;
  23. }
  24. ListNode node = map.get(key);
  25. node.pre.next = node.next;
  26. node.next.pre = node.pre;
  27. return node.val;
  28. }
  29.  
  30. public void put(int key,int value){
  31. if (get(key)!=-1){
  32. map.get(key).val = value;
  33. return;
  34. }
  35.  
  36. ListNode node = new ListNode(key,value);
  37. map.put(key,node);
  38. moveToTail(node);
  39.  
  40. if (map.size() > capacity){
  41. map.remove(head.next.key);
  42. head.next = head.next.next;
  43. head.next.pre = head;
  44. }
  45.  
  46. }
  47.  
  48. //把节点移动到尾巴
  49. private void moveToTail(ListNode node) {
  50. node.pre = tail.pre;
  51. tail.pre = node;
  52. node.pre.next = node;
  53. node.next = tail;
  54. }
  55.  
  56. //定义双向链表节点
  57. private class ListNode{
  58. int key;
  59. int val;
  60. ListNode pre;
  61. ListNode next;
  62.  
  63. //初始化双向链表
  64. public ListNode(int key,int val){
  65. this.key = key;
  66. this.val = val;
  67. pre = null;
  68. next = null;
  69. }
  70. }
  71. }

到此这篇关于浅谈java如何实现Redis的LRU缓存机制的文章就介绍到这了,更多相关java实现Redis的LRU缓存机制内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/xiaowanzi_zj/article/details/117906792