天天看點

Guava中Cache的使用

緩存的主要作用是暫時在記憶體中儲存業務系統的資料處理結果,并且等待下次通路使用。在日常開發的很多場合,由于受限于硬碟IO的性能或者我們自身業務系統的資料處理和擷取可能非常費時,當我們發現我們的系統這個資料請求量很大的時候,頻繁的IO和頻繁的邏輯處理會導緻硬碟和CPU資源的瓶頸出現。緩存的作用就是将這些來自不易的資料儲存在記憶體中,當有其他線程或者用戶端需要查詢相同的資料資源時,直接從緩存的記憶體塊中傳回資料,這樣不但可以提高系統的響應時間,同時也可以節省對這些資料的處理流程的資源消耗,整體上來說,系統性能會有大大的提升

Guava中Cache的兩種建立方式

在Guava中可以通過cacheLoader和callable callback兩種方式來建立緩存。通過這兩種方法建立的cache,和通常用map來緩存的做法比,不同在于,這兩種方法都實作了一種邏輯——從緩存中取key X的值,如果該值已經緩存過了,則傳回緩存中的值,如果沒有緩存過,可以通過某個方法來擷取這個值。但不同的在于cacheloader的定義比較寬泛,是針對整個cache定義的,可以認為是統一的根據key值load value的方法。而callable的方式較為靈活,允許你在get的時候指定。

cacheLoader方式

測試代碼

@Test
    public void testLoadingCache() throws Exception {
        LoadingCache<String, String> cahceBuilder = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                System.out.println("請求的key為" + key + "在緩存中不存在,通過load方法擷取key.");
                String strProValue = "hello " + key + "!";
                return strProValue;
            }

        });

        // 第一次到緩存裡面key為peida的資料,緩存不存在通過,load加載,并儲存到緩存裡面
        System.out.println("a value:" + cahceBuilder.get("a"));
        // 第二次擷取key為peida的資料,緩存已經存在,直接在緩存裡面傳回
        System.out.println("a value:" + cahceBuilder.get("a"));

        // 往緩存裡面存放資料
        cahceBuilder.put("b", "bbbb");
        // 緩存已經存在資料了,直接擷取
        System.out.println("b value:" + cahceBuilder.get("b"));
    }
           

輸出結果

請求的key為a在緩存中不存在,通過load方法擷取key.
a value:hello a!
a value:hello a!
b value:bbbb
           

callable callback方式

測試代碼

@Test
public void testcallableCache() throws Exception {
    Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize().build();
    String resultVal = cache.get("a", new Callable<String>() {
        public String call() {
            String strProValue = "hello " + "a" + "!";
            return strProValue;
        }
    });
    System.out.println("a value : " + resultVal);

    resultVal = cache.getIfPresent("b");
    System.out.println("a value : " + resultVal);
}
           

輸出結果

a value : hello a!
a value : null
           

cache的參數說明

回收的參數:

  1. 大小的設定:CacheBuilder.maximumSize(long) CacheBuilder.weigher(Weigher) CacheBuilder.maxumumWeigher(long)

  2. 時間:expireAfterAccess(long, TimeUnit) expireAfterWrite(long, TimeUnit)

  3. 引用:CacheBuilder.weakKeys() CacheBuilder.weakValues() CacheBuilder.softValues()

  4. 明确的删除:invalidate(key) invalidateAll(keys) invalidateAll()

  5. 删除監聽器:CacheBuilder.removalListener(RemovalListener)

  

refresh機制:

  1. LoadingCache.refresh(K) 在生成新的value的時候,舊的value依然會被使用。

  2. CacheLoader.reload(K, V) 生成新的value過程中允許使用舊的value

  3. CacheBuilder.refreshAfterWrite(long, TimeUnit) 自動重新整理cache

guava Cache資料移除

guava做cache時候資料的移除方式,在guava中資料的移除分為被動移除和主動移除兩種。

  被動移除資料的方式,guava預設提供了三種方式:

  1.基于大小的移除:看字面意思就知道就是按照緩存的大小來移除,如果即将到達指定的大小,那就會把不常用的鍵值對從cache中移除。

  定義的方式一般為 CacheBuilder.maximumSize(long),還有一種一種可以算權重的方法,個人認為實際使用中不太用到。就這個常用的來看有幾個注意點,

    其一,這個size指的是cache中的條目數,不是記憶體大小或是其他;

    其二,并不是完全到了指定的size系統才開始移除不常用的資料的,而是接近這個size的時候系統就會開始做移除的動作;

    其三,如果一個鍵值對已經從緩存中被移除了,你再次請求通路的時候,如果cachebuild是使用cacheloader方式的,那依然還是會從cacheloader中再取一次值,如果這樣還沒有,就會抛出異常

  2.基于時間的移除:guava提供了兩個基于時間移除的方法

    expireAfterAccess(long, TimeUnit) 這個方法是根據某個鍵值對最後一次通路之後多少時間後移除

    expireAfterWrite(long, TimeUnit) 這個方法是根據某個鍵值對被建立或值被替換後多少時間移除

  3.基于引用的移除:

  這種移除方式主要是基于java的垃圾回收機制,根據鍵或者值的引用關系決定移除

  主動移除資料方式,主動移除有三種方法:

  1.單獨移除用 Cache.invalidate(key)

  2.批量移除用 Cache.invalidateAll(keys)

  3.移除所有用 Cache.invalidateAll()

  如果需要在移除資料的時候有所動作還可以定義Removal Listener,但是有點需要注意的是預設Removal Listener中的行為是和移除動作同步執行的,如果需要改成異步形式,可以考慮使用RemovalListeners.asynchronous(RemovalListener, Executor)

繼續閱讀