Google的Guava cache 應用

jopen 11年前發布 | 52K 次閱讀 緩存組件 Guava cache

Guava Cache 創建
基本上可以通過兩種方式來創建cache:

cacheLoader
callable callback


通過這兩種方法創建的cache,和通常用map來緩存的做法比,不同在于,這兩種方法都實現了一種邏輯——從緩存中取key X的值,如果該值已經緩存過了,則返回緩存中的值,如果沒有緩存過,可以通過某個方法來獲取這個值。

但不同的在于cacheloader的定義比較寬泛,是針對整個cache定義的,可以認為是統一的根據key值load value的方法。

而callable的方式較為靈活,允許你在get的時候指定。

下面是兩種方法的例子:

首先是基于cacheloader的方法

@Test
public void testCacheBuilder() throws ExecutionException {

    LoadingCache<String, String> graphs = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .build(new CacheLoader<String, String>() {
            public String load(String key) {
                // 這里是key根據實際去取值的方法
                return "value";
            }
        });

    String resultVal = graphs.get("testKey");
    System.out.println(resultVal);
}


 其次是基于實現callable的方法:

@Test
public void testCallable() throws ExecutionException {
    // 沒有使用CacheLoader
    Cache<String, String> cache = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .build();

    String resultVal = cache.get("testKey", new Callable<String>() {
        public String call() {
            // 這里先根據key實際去取值的方法
            return "value";
        }
    });
    System.out.println(resultVal);
}

Guava Cache 數據的移除
被動移除數據的方式,guava默認提供了三種方式:


基于大小的移除

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

定義的方式一般為 CacheBuilder.maximumSize(long),官方還介紹了一種可以算權重的方法,個人認為實際使用中不太用到,暫不討論。

就這個常用的來看有幾個注意點,
其一,這個size指的是cache中的條目數,不是內存大小或是其他;
其二,并不是完全到了指定的size系統才開始移除不常用的數據的,而是接近這個size的時候系統就會開始做移除的動作;
其三,如果一個鍵值對已經從緩存中被移除了,你再次請求訪問的時候,如果cachebuild是使用cacheloader方式的,那依然還是會從cacheloader中再取一次值,如果這樣還沒有,就會拋出異常


基于時間的移除

      guava提供了兩個基于時間移除的方法
      expireAfterAccess(long, TimeUnit)  這個方法是根據某個鍵值對最后一次訪問之后多少時間后移除
      expireAfterWrite(long, TimeUnit)    這個方法是根據某個鍵值對被創建或值被替換后多少時間移除

基于引用的移除

      這種移除方式主要是基于java的垃圾回收機制,根據鍵或者值的引用關系決定移除,個人對垃圾回收這塊不是非常了解,竊以為不太可靠。。也不常用。。所以沒有研究,歡迎補充。


主動移除數據方式 
       主動移除有三種方法: 
             單獨移除用 Cache.invalidate(key)
     批量移除用 Cache.invalidateAll(keys)
             移除所有用 Cache.invalidateAll()


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

Guava Cache 的清空,刷新及統計功能
主要介紹guava cache的清空,刷新和統計的功能。 
緩存數據的清空 
      guava沒有提供自動觸發清空緩存數據的功能,而是提供了一種手工調用的方式,使用者需要通過Cache.cleanUp()的方式來清空緩存。

      所以一般可以有兩種選擇,一種是通過某個請求來觸發清空動作,這種相當于按需清空,另一種則是通過定時任務,亦成為調度程序來清空,這種相當于與按時清空

緩存數據的刷新 
      guava沒有提供類似refreshall的方法刷新緩存中的所有值,而只是提供了 LoadingCache.refresh(K)方法,用于刷新某個鍵值對,這里有趣的是刷新動作是異步的,也就是在值被徹底刷新之前,如果有人取這個key的值,返回的還是沒有刷新的值。

      如果你希望定義自己的刷新行為,可以重寫 CacheLoader.reload(K, V)方法

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
   .maximumSize(1000)
   .refreshAfterWrite(1, TimeUnit.MINUTES)
   .build(
       new CacheLoader<Key, Graph>() {
         public Graph load(Key key) { // no checked exception
           return getGraphFromDatabase(key);
         }

         public ListenableFuture<Graph> reload(final Key key, Graph prevGraph) {
           if (neverNeedsRefresh(key)) {
             return Futures.immediateFuture(prevGraph);
           } else {
             // asynchronous!
             return ListenableFutureTask.create(new Callable<Graph>() {
               public Graph call() {
                 return getGraphFromDatabase(key);
               }
             });
           }
         }
       });
緩存數據統計 
      可以通過 CacheBuilder.recordStats()方法打開統計, Cache.stats()方法會返回一個CacheStats對象,里面有緩存條目訪問率等數據,如果你的緩存需要做一些調優,可以參考這里的數據。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!