背景
linkedhashmap繼承自hashmap,内部提供了一個removeeldestentry方法,該方法正是實作lru政策的關鍵所在,
且hashmap内部專門為linkedhashmap提供了3個專用回調方法,afternodeaccess、
afternodeinsertion、afternoderemoval,這3個方法的字面意思非常容易了解,就是節點通路後、節點插入後、節點删除後
分别執行的行為。基于以上行為linkedhashmap就可以實作一個lrucache的功能了。
關于linkedhashmap的eldest:eldest字面意思為最老的,linkedhashmap中有個叫做accessorder的字
段,當accessorder為true時表示linkedhashmap内部節點按照通路次數排序,最老的節點也就是通路最少的節點。當
accessorder為false時表示linkedhashmap内部節點按照插入順序排序,最老的節點也就是最早插入的節點,該值預設為
false。
實作
自己實作lrucache隻需覆寫removeeldestentry這個方法即可,代碼如下
private static class lrucache<k, v> extends linkedhashmap<k, v>
{
private static final long serialversionuid = -9111855653176630846l;
private static int max_elements;
public lrucache(int initcap, int maxsize) throws illegalargumentexception
{
super(initcap, 0.75f, true);
if (maxsize < 0)
throw new illegalargumentexception();
max_elements = maxsize;
}
@override
protected boolean removeeldestentry(map.entry<k, v> eldest)
return size() > max_elements;
}
以上代碼需要一個max_elements變量限制最大存儲節點個數,插入節點時判斷 如果當
前節點個數已經超過了這個值則會根據lru政策将通路最少的那個節點删除,這裡需要注意,預設linkedhashmap保證的是插入順序,也就是節點按
照插入先後來排序的,是以就算删除也是删除最先插入的節點,但是我們在構造函數中傳入了一個true,這個參數決定了linkedhashmap内部的節
點按照什麼方式排序,參數為true時說明内部節點按照最近通路的時間排序,為false時說明按照插入順序排序。至此已完成了一個簡易的
lrucache實作。
注意
由于linkedhahsmap本身實作不是線程安全的,也就是說這個lrucache也不是線程安全的,如果想要能多線程通路的話,可以這樣使用
它:lrucache cache = collections.synchronizedmap(new lrucache(10,
10))。這樣cache就可以在多線程下執行get/put等操作了,但是,用這種方式得到的cache在多線程周遊時還是不安全的。是以不能在多線程
下周遊cache,官方文檔也建議在周遊synchronizedmap時使用map本身做同步。
來源:51cto