如何用LinkedHashMap實現LRU緩存算法

緩存這個東西就是爲了提高運行速度的,由於緩存是在寸土寸金的內存裏面,不是在硬盤裏面,所以容量是很有限的。LRU這個算法就是把最近一次使用時間離現在時間最遠的數據刪除掉。先說說List:每次訪問一個元素後把這個元素放在 List一端,這樣一來最遠使用的元素自然就被放到List的另一端。緩存滿了t的時候就把那最遠使用的元素remove掉。但更實用的是HashMap。因爲List太慢,要刪掉的數據總是位於List底層數組的第一個位置,刪掉之後,後面的數據要向前補位。。所以複雜度是O(n),那就用鏈表結構的LinkedHashMap唄~,LinkedHashMap默認的元素順序是put的順序,但是如果使用帶參數的構造函數,那麼LinkedHashMap會根據訪問順序來調整內部 順序。 LinkedHashMap的get()方法除了返回元素之外還可以把被訪問的元素放到鏈表的底端,這樣一來每次頂端的元素就是remove的元素。

構造函數如下:

public LinkedHashMap (int initialCapacity, float loadFactor, boolean accessOrder);

 initialCapacity   初始容量

 loadFactor    加載因子,一般是 0.75f

accessOrder   false 基於插入順序  true  基於訪問順序(get一個元素後,這個元素被加到最後,使用了LRU  最近最少被使用的調度算法)

來個例子吧:
[java] view plaincopy
  1. import java.util.*;  
  2.   
  3. class Test  
  4. {  
  5.     public static void main(String[] args) throws Exception{  
  6.       
  7.         Map<Integer,Integer> map=new LinkedHashMap<Integer,Integer>(10,0.75f,true);  
  8.         map.put(9,3);  
  9.         map.put(7,4);  
  10.         map.put(5,9);  
  11.         map.put(3,4);  
  12.         //現在遍歷的話順序肯定是9,7,5,3  
  13.         //下面訪問了一下9,3這個鍵值對,輸出順序就變嘍~  
  14.         map.get(9);  
  15.         for(Iterator<Map.Entry<Integer,Integer>> it=map.entrySet().iterator();it.hasNext();){  
  16.             System.out.println(it.next().getKey());  
  17.         }  
  18.     }  
  19. }  
輸出
7
5
3
9
好玩吧~
下面開始實現LRU緩存嘍~
[java] view plaincopy
  1. import java.util.*;  
  2. //擴展一下LinkedHashMap這個類,讓他實現LRU算法  
  3. class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V>{  
  4.     //定義緩存的容量  
  5.     private int capacity;  
  6.     private static final long serialVersionUID = 1L;  
  7.     //帶參數的構造器     
  8.     LRULinkedHashMap(int capacity){  
  9.         //調用LinkedHashMap的構造器,傳入以下參數  
  10.         super(16,0.75f,true);  
  11.         //傳入指定的緩存最大容量  
  12.         this.capacity=capacity;  
  13.     }  
  14.     //實現LRU的關鍵方法,如果map裏面的元素個數大於了緩存最大容量,則刪除鏈表的頂端元素  
  15.     @Override  
  16.     public boolean removeEldestEntry(Map.Entry<K, V> eldest){   
  17.         System.out.println(eldest.getKey() + "=" + eldest.getValue());    
  18.         return size()>capacity;  
  19.     }    
  20. }  
  21. //測試類  
  22. class Test{  
  23. public static void main(String[] args) throws Exception{  
  24.   
  25.     //指定緩存最大容量爲4  
  26.     Map<Integer,Integer> map=new LRULinkedHashMap<Integer,Intege>(4);  
  27.     map.put(9,3);  
  28.     map.put(7,4);  
  29.     map.put(5,9);  
  30.     map.put(3,4);  
  31.     map.put(6,6);  
  32.     //總共put了5個元素,超過了指定的緩存最大容量  
  33.     //遍歷結果  
  34.         for(Iterator<Map.Entry<Integer,Integer>> it=map.entrySet().iterator();it.hasNext();){  
  35.             System.out.println(it.next().getKey());  
  36.         }  
  37.     }  
  38. }  
輸出結果如下
9=3
9=3
9=3
9=3
9=3
7
5
3
6
分析一下:使用帶參數構造器,且啓用LRU模式的LinkedHashMap會在每次有新元素加入的時候,判斷當前儲存元素是否超過了緩存上限,也就是執行
一次removeEldestEntry方法,看最後的遍歷結果,發現果然把9刪除了,LRU發揮作用了~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章