linkedhashmap是hashmap的子類,和hashmap不同的是它內部還使用了乙個雙向鍊錶將所有元素連線在了一起,然後基於這個雙向鍊錶實現了fifo和lru兩種元素訪問策略。本文的目的是連線linkedhashmap內部的實現機制,然後基於它實現乙個簡單的lru。
linkedhashmap中每個元素的資料結構如下:
可以看出它是對hashmap的node結構進行了拓展
linkedhashmap中元素的遍歷:
所以內部其實就是鍊錶的遍歷,這個實現就要比hashmap簡單多的,hashmap是按照table的順序進行遍歷。既然是按照鍊錶遍歷的,那麼它的fifo和lru訪問策略是如何實現的呢?
(ps: linkedhashmap的fifo & lru訪問策略說明:
linkedhashmap內部使用accessorder屬性來控制使用哪種策略,預設為false,即fifo,鍊錶中的順序就是元素插入時的順序,遍歷是是按照元素插入的順序訪問的。設定為true時就是lru
策略。此時會調整鍊錶中元素的順序,會把訪問的節點放入鍊錶的末尾(tail位置,訪問時都是從head開始),每次刪除head指向的元素就可以達到lru的效果。
由於linkedhashmap是hashmap的子類,很多方法都是使用父類hashmap中的方法,所以此處就不再另行解釋了,有興趣的可以看下我之前寫的分析hashmap的那篇文章,本文只分析幾個linkedhashmap有過改動或者特有的幾個方法。
)put()插入資料(lru模式下會刪除超過容量的元素):
呼叫的是hashmap中的put(),不同的是重寫了其中的newnode()方法,完成了鍊錶的構建,將元素新增到鍊錶的尾部。
lru模式下,會刪除超過容量的元素,從head開始刪除:
removenode()方法內部會呼叫hashmap中的remove()方法刪除map中的元素,接著還會呼叫afternoderemoval(node)
可以看出來,remove()方法會刪除map中的資料,但是鍊錶中元素的順序不會做調整。
get()獲取元素(lru模式下還會調整鍊錶中元素的順序):
afternodeaccess()本質上就是將元素從當前位置移到鍊錶末尾:
(ps: 從++modcount可以看出,linkedhashmap是非執行緒安全的)
基於linkedhashmap實現乙個簡單的lrumap:
參考:public class lrumapextends linkedhashmapprotected void add(k value)
@override
protected boolean removeeldestentry(map.entryeldest)
}
//測試**//輸出為:b d clrumapcache = new lrumap<>(3);
cache.add("a");
cache.add("b");
cache.add("c");
cache.add("d");
cache.get("c");
cache.foreach((k, v) -> system.out.println(k));
其實這個**繼承linkedhashset會更加簡單一點
AbstractCollection原始碼分析
abstractcollection抽象類提供了collection的骨架實現,collection分析請看 這裡直接看它的 是如何實現的.public abstract iterator iterator 該方法沒有實現.public abstract int size 該方法沒有實現.publi...
ThreadPoolExecutor原始碼閱讀
執行緒池解決兩個問題 一是復用執行緒,減少建立銷毀執行緒帶來系統開銷 二是限定系統資源使用邊界,避免大量執行緒消耗盡系統記憶體 適用於互不依賴,執行時間短,不需要對執行緒控制操作的執行緒 新增任務時,1.若執行緒數量小於corepoolsize,則新增執行緒執行任務 2.若執行緒數量大於等於core...
OrangePi One Android 原始碼編譯
一 系統環境搭建參照 二 lichee原始碼編譯 1.檢視help build.sh h2.配置核心 cd linux 3.4 make arch arm menuconfig 進入配置頁面,上下移動列表,空格是選擇列表,左右移動選擇退出選項 3.首次編譯執行清除 在 lichee linux3.4...