天天看點

Java 自定義實作 LRU 緩存算法

背景

linkedhashmap繼承自hashmap,内部提供了一個removeeldestentry方法,該方法正是實作lru政策的關鍵所在,

且hashmap内部專門為linkedhashmap提供了3個專用回調方法,afternodeaccess、

afternodeinsertion、afternoderemoval,這3個方法的字面意思非常容易了解,就是節點通路後、節點插入後、節點删除後

分别執行的行為。基于以上行為linkedhashmap就可以實作一個lrucache的功能了。

Java 自定義實作 LRU 緩存算法

關于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