前言:
在學習LRU算法的時候,看到LruCache源碼實現是基於LinkedHashMap,今天學習一下LinkedHashMap的好處以及如何實現lru緩存機制的。
需求背景:
LRU這個算法就是把最近一次使用時間離現在時間最遠的數據刪除掉,而實現LruCache將會頻繁的執行插入、刪除等操作,我們就會想到使用LinkedList,但是我們又要基於Key-Value來保存數據,這個時候我們就會想起HashMap,但是HashMap不能像linkedList那樣保留數據的插入順序,如果要使用HashMap的話可以使用它的一個子類LinkedHashMap。
LinkedHashMap介紹:
LinkedHashMap是Map接口的哈希表和鏈接列表實現,具有可預知的迭代順序。此實現提供所有可選的映射操作,並允許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恆久不變, LinkedHashMap實現與HashMap的不同之處在於,后者維護着一個運行於所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序可以是插入順序或者是訪問順序。根據鏈表中元素的順序可以分為:按插入順序的鏈表,和按訪問順序(調用get方法)的鏈表。默認是按插入順序排序,如果指定按訪問順序排序,那么調用get方法后,會將這次訪問的元素移至鏈表尾部,不斷訪問可以形成按訪問順序排序的鏈表。 可以重寫removeEldestEntry方法返回true值指定插入元素時移除最老的元素。更多關於LinkedHashMap的知識介紹請查看這篇博客,博客地址:http://www.cnblogs.com/children/archive/2012/10/02/2710624.html
LinkedHashMap使用:
因為我們這里為了實現LRU算法,排序方式 設置為true 訪問順序排序
int initialCapacity = 10;//初始化容量 float loadFactor = 0.75f;//加載因子,一般是 0.75f boolean accessOrder = true;//排序方式 false 基於插入順序 true 基於訪問順序 Map<String, Integer> map = new LinkedHashMap<>(initialCapacity, loadFactor, accessOrder);
具體看下效果:
for (int i = 0; i < 10; i++) { map.put(String.valueOf(i), i); } //訪問前順序 for (Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator(); it.hasNext(); ) { Map.Entry<String, Integer> next = it.next(); Log.e(TAG, "linkedMap--before-->" + next.getKey()); } //模擬訪問 map.get("5"); //訪問后數據 for (Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator(); it.hasNext(); ) { Map.Entry<String, Integer> next = it.next(); Log.e(TAG, "linkedMap--after-->" + next.getKey()); } }
運行結果發現訪問過的5未知發生了變化 說明是基於訪問排序的。我們接下來再看下如何移除過期的。
final int initialCapacity = 10;//初始化容量 float loadFactor = 0.75f;//加載因子,一般是 0.75f boolean accessOrder = true;//排序方式 false 基於插入順序 true 基於訪問順序 //Map<String, Integer> map = new LinkedHashMap<>(initialCapacity, loadFactor, accessOrder); Map<String, Integer> map = new LinkedHashMap(initialCapacity, loadFactor, accessOrder) { @Override protected boolean removeEldestEntry(Entry eldest) { return size() > initialCapacity; } }; for (int i = 0; i < 15; i++) { map.put(String.valueOf(i), i); } //訪問前順序 for (Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator(); it.hasNext(); ) { Map.Entry<String, Integer> next = it.next(); Log.e(TAG, "linkedMap--before-->" + next.getKey()); }
我們容量定的10個,我們插入15個 我們發現最先插入的五個不見了,說明LRU算法起到效果了。