LRU算法的實現


需求

隨着公司的業務越來越復雜,需要提供一個用戶系統,供各個業務系統來查詢用戶的基本信息。且業務方對用戶信息的查詢頻率很高,設計的用戶系統需要注意性能。

  • 初始設計 考慮到性能,可以在內存中創建一個哈希表作為緩存,每當查找一個用戶時,會現在哈希表中進行查詢,查詢不到再去數據庫查詢。
  • 初始設計存在的問題 隨着用戶量不斷增大,可能會因為哈希表逐漸增大導致內存某一天會被撐爆。
  • 初始設計的優化使用LRU算法(內存管理算法,Least Recently Used),最近最少使用的思想。算法基於一種假設:長期不被使用的數據,在未來被用到的幾率也不大。因此,當數據所占內存達到一定閾值時,我們要移除掉最近最少被使用的數據。

LRU算法

在LRU算法中,使用一種叫作“哈希鏈表”的數據結構。哈希表由若干個key-value組成,邏輯上這些key-value是無所謂排序的。但在哈希鏈表中,這些key-value被一個鏈條串在一起,不再是無序的了,而是有 了固定的排列順序。每一個key-value都有前驅key-value、后繼key-value。所以我們可以把key-value按照最后使用的時間來進行排序。鏈表的尾部是最近被使用的,頭部是最近被使用最少甚至沒有被使用過的key-value。所以,當緩存容量達到上限時,會先刪除鏈表最左端的值,再把新的值插入到鏈表的最右端。

LRU算法實現

哈希鏈表的結構:

 

 注意點: 刪除節點的同時,記得把節點的key也要從hashMap中刪除

  1 package blogSrc;
  2 
  3 import java.util.HashMap;
  4 
  5 public class LRUCache {
  6     private Node head;
  7     private Node end;
  8 
  9     private HashMap<String,Node> hashMap;
 10     private int limit;  //緩存上限
 11 
 12     public LRUCache(int limit){
 13         this.limit = limit;
 14         this.hashMap = new HashMap<String,Node>();
 15     }
 16 
 17     //向鏈表中添加節點
 18     public void addNode (Node node){
 19         if (head == null){  //空鏈
 20             head = node;
 21         }
 22 
 23         if(end != null) {  //節點添加到尾部
 24             end.next = node;
 25             node.pre = end;
 26             node.next = null;
 27         }
 28         end = node;
 29     }
 30 
 31     //從鏈表中移除節點
 32     public String  removeNode(Node node){
 33         if(head == end && node == head){  //鏈表只有一個節點
 34             head = null;
 35             end = null;
 36         }else if (node == end){ //node為最后一個節點
 37             end.pre.next = null;
 38             end = end.pre;
 39         }else if (node == head){  //node為第一個節點
 40             head.next.pre = null;
 41             head = head.next;
 42         }else {  //node為中間節點
 43             node.pre.next = node.next;
 44             node.next.pre = node.pre;
 45         }
 46         return node.key;
 47     }
 48 
 49     //刷新鏈表,將最近使用的節點放置到鏈表末尾
 50     public void refreshNode(Node node){
 51          if (node == end){
 52              return;
 53          }
 54          removeNode(node);  //刪除節點
 55          addNode(node); //添加節點
 56     }
 57 
 58     //根據節點的key值,獲取鏈表中該節點的value值
 59     public String get(String key){
 60         Node node = hashMap.get(key);
 61         if (node == null){
 62             return null;
 63         }
 64         refreshNode(node);
 65         return node.value;
 66     }
 67 
 68     //向鏈表上添加key-value
 69     public void put(String key, String value){
 70         Node node = hashMap.get(key);
 71         if (node == null){
 72             if (hashMap.size() >= limit){
 73                 String oldKey = removeNode(head);  //刪除節點
 74                 hashMap.remove(oldKey);  //同時需要把節點的key也從hashmap中刪除
 75             }
 76             node = new Node(key,value);
 77             addNode(node);
 78             hashMap.put(key,node);
 79         }else {
 80             node.value = value;
 81             refreshNode(node);
 82         }
 83     }
 84 
 85     //從鏈表上刪除指定key的數據
 86     public void remove(String key){
 87         Node node = hashMap.get(key);
 88         if (node == null){
 89             return ;
 90         }
 91         removeNode(node);
 92         hashMap.remove(key);
 93     }
 94 
 95     class Node {
 96         public Node next;
 97         public Node pre;
 98         public String key;
 99         public String value;
100         Node(String key, String value){
101             this.key = key;
102             this.value = value;
103         }
104 
105         public String getNextKey() {
106             return next.getKey();
107         }
108 
109         public String getPreKey() {
110             return pre.getKey();
111         }
112 
113         public String getKey() {
114             return key;
115         }
116 
117         public String getValue() {
118             return value;
119         }
120     }
121 
122 
123     public static void main(String[] args){
124         LRUCache lruCache = new LRUCache(10);
125         lruCache.put("001","用戶1信息");
126         lruCache.put("002","用戶2信息");
127         lruCache.put("003","用戶3信息");
128         lruCache.put("004","用戶4信息");
129         lruCache.get("003");
130         System.out.println("Now End Node Key is: " + lruCache.end.getKey()+ ",Value is: " +lruCache.end.getValue());
131         lruCache.put("002","用戶2信息更新");
132         System.out.println("Now End Node Key is: " + lruCache.end.getKey() + ",Value is: " +lruCache.end.getValue() );
133         lruCache.put("006","用戶6信息");
134         System.out.println("Now End Node Key is: " + lruCache.end.getKey()+ ",Value is: " +lruCache.end.getValue());
135     }
136 }

 

 結果:

Now End Node Key is: 003,Value is: 用戶3信息
Now End Node Key is: 002,Value is: 用戶2信息更新
Now End Node Key is: 006,Value is: 用戶6信息

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM