1. 程式人生 > >LinkedHashMap實現本地快取

LinkedHashMap實現本地快取

【--親測有效--】

在 Java 中使用本地快取最簡單的方式就是使 HashMap 或者 ConcurrentHashMap,對於只讀場景,兩者都可以使用,對於快取更新的場景,可以使用 ConcurrentHashMap 來保證資料的一致性,二者的使用方式非常簡單,這裡不再贅述。

+

​ 另外,在 Java 中基於 LinkedHashMap 類,提供了一個自動清理最老元素的功能,,基於這個特質,可以將改造成一個LRU(Least Recently Used ,表示最近最少使用)快取使用。

​ 將 LinkedHashMap 改造成快取,需要重寫 LinkedHashMap 中 removeEldestEntry(Map.Entry<K,V> eldest),這個方法,改方法是 protected 方法,不能直接呼叫,只能繼承重寫。當插入資料時(呼叫 put 或者 putAll 時)會呼叫這個方法用於判斷是否移除最老元素,返回 true 表示刪除,否則不刪除,Java 原始碼中,該方法直接返回 false,如下圖所示,看來是專門留給開發者擴充套件額。

案例程式碼如下:


package com.github.coderxing.book.code.chapter4;

public class LruCache<K, V> extends LinkedHashMap<K, V> {
    private static final long serialVersionUID = 4504158311663914052L;

    private int maxCacheSize;

    public LruCache(int maxCacheSize) {

        // 第三個引數為 accessOrder,預設為false。表示按照按照訪問順序排列元素,最近訪問的元素會排雷在隊末尾

        super(maxCacheSize, 0.75f, true);

        this.maxCacheSize = maxCacheSize;

    }

    @Override
    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {

        // 當達到預設快取上限時刪除最老元素
        return this.size() >= maxCacheSize + 1;
    }


}

測試程式碼如下:


LruCache<String, String> cache = new LruCache<String, String>(3);

cache.put("k1", "v1");

System.out.println("test1:"+cache);

cache.put("k2", "v2");

System.out.println("test2:"+cache);

cache.put("k3", "v3");

System.out.println("test3:"+cache);

cache.put("k4", "v4");

System.out.println("test4:"+cache);

//因為我們在後再物件時,accessOrder設定為true,訪問一次 k2,k2對應的元素就會排在隊尾部,被看做最新元素

cache.get("k2");

System.out.println("test5:"+cache);


Map<String,String> multiKV = new HashMap<String,String>();

multiKV.put("k5", "k5");

multiKV.put("k6", "k6");

cache.putAll(multiKV);

System.out.println("test5:"+cache);

輸出內容為:


test1:{k1=v1}

test2:{k1=v1, k2=v2}

test3:{k1=v1, k2=v2, k3=v3}

test4:{k2=v2, k3=v3, k4=v4}

test5:{k3=v3, k4=v4, k2=v2}

test5:{k2=v2, k5=k5, k6=k6}

​ 從例子中可見,通過簡單的方式就可以快速實現一個LRU快取類,但 LinkedHashMap 不是執行緒安全額,在面對高併發的情況下還需要進一步封裝,比如通過 synchronized 封裝代理方法,如:


public V putCache(K key, V value) {
  synchronized(this){
    return this.put(key, value);
  }
}

或者 Collections.synchronizedMap 進行封裝,例如:

```java

Map<String, String> cache = Collections.synchronizedMap(new LruCache<String, String>(3));

```

​ 使用 LinkedHashMap 可以簡單快速實現一個快取框架,要想獲得更好的效能,和更強大的功能,可以參考本週後面兩節介紹的 Ehcache 和 Google Guava Cache 。