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);- 1
- 2
initialCapacity 初始容量
loadFactor 加載因子,一般是 0.75f
accessOrder false 基于插入順序 true 基于訪問順序(get一個元素后,這個元素被加到最后,使用了LRU 最近最少被使用的調度算法)
看一下LinkedHashMap的相關實現源碼吧:
// 雙向鏈表的 head節點 private transient Entry<K,V> header;// 訪問順序 true:訪問順序;false:插入順序 private final boolean accessOrder;// get方法 每個get之后,都要進行recordAccess操作 public V get(Object key) {Entry<K,V> e = (Entry<K,V>)getEntry(key);if (e == null)return null;e.recordAccess(this);return e.value; }// recordAccess 方法中,先remove該節點,再在head之間添加節點,表示最近訪問了 void recordAccess(HashMap<K,V> m) {LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;if (lm.accessOrder) {lm.modCount++;remove();addBefore(lm.header);} }// 刪除該節點 private void remove() {before.after = after;after.before = before; }private void addBefore(Entry<K,V> existingEntry) {after = existingEntry;before = existingEntry.before;before.after = this;after.before = this; }// 添加新的entry時,如果需要刪除eldest節點,就會刪除head.after,如果是訪問順序,也就是最早以前訪問的節點 void addEntry(int hash, K key, V value, int bucketIndex) {super.addEntry(hash, key, value, bucketIndex);// Remove eldest entry if instructedEntry<K,V> eldest = header.after;if (removeEldestEntry(eldest)) {removeEntryForKey(eldest.key);} } // 默認的removeEldestEntry方法是返回false的,也就是不會進行刪除,而是進行擴容protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {return false; } 這是實現LRU的關鍵,我們可以重寫這個方法,讓其刪除eldest entry;- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
來個例子吧:?
import java.util.*;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
輸出?
7?
5?
3?
9
好玩吧~?
下面開始實現LRU緩存嘍~
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
輸出結果如下?
9=3?
9=3?
9=3?
9=3?
9=3?
7?
5?
3
分析一下:使用帶參數構造器,且啟用LRU模式的LinkedHashMap會在每次有新元素加入的時候,判斷當前儲存元素是否超過了緩存上限,也就是執行?
一次removeEldestEntry方法,看最后的遍歷結果,發現果然把9刪除了,LRU發揮作用了~
總結
以上是生活随笔為你收集整理的LinkedHashMap实现LRU缓存算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java内存泄漏总结
- 下一篇: 一致性Hash(Consistent H