前言:
在學習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演算法起到效果了。