Guava Cache

內容摘要算法

  • 寫入數據到緩存
    • 手動寫入 (put)
    • 自動加載(按需加載)
  • 數據清理
    • 過時、清理
      • 基於容量的清理觸發條件
      • 基於時間的過時方案
      • 基於Reference Key,Value
      • 手動移除 (顯式移除)
    • RemoveListener
    • 數據清理時機
  • refresh
  • 配置說明
  • 場景說明

 

 

一、寫數據到緩存

 

1.1 手動寫入 put

Guava Cache 底層是由一個ConcurrentMap實現的,那麼底層必然支持兩個常規的put:put(k,v), putIfAbsent(k,v)。緩存

從類圖上來看,基於Guava Cache實現的cache必然是有一個put(k,v)方法的,直接放k,v對到cache中,並替換掉原有的數據。從接口Cache 來看,只提供了一個put(k,v)方法,底層是一個ConcurrentMap,那麼putIfAbsent(k,v)的特性好像被丟棄了。若是你但願使用putIfAbsent,那麼能夠調用Cache.asMap().putIfAbsent(k,v)。併發

 

 

1.2 自動加載(按需加載)

 

除了上面的put直接寫入cache方式外,Guava Cache還提供了兩種實現了get-if-absent-compute語義的方式。異步

所謂的get-if-absent-compute語義是說:在調用get方法時,若是發現指定的值不存在,則經過加載、計算等方式來提供值。也能夠將這個語義理解爲lazy load(懶加載、按需加載)。高併發

 

這兩種方式分別爲:Cache.get(key, Callable) 、LoadingCache。ui

 

Cache.get(key, Callable) 在調用get時,指定一個Callable,若是值不存在時,調用Callable來計算值。計算到值後放入Cache中,並返回結果。spa

 

LoadingCache 必須有一個CacheLoader配合一塊兒使用,LoadingCache與CacheLoader的幾個方法的調用關係:線程

LoadingCache.get(k) ->  CacheLoader.load(k)接口

LoadingCache.refresh(k) ->   CacheLoader.reload(k)內存

LoadingCache.getAll(keys) -> CacheLoader.loadAll(keys)

CacheLoader是不保證必定能夠加載成功,因此它的全部方法都是有異常的。

 

二、數據清理

任何一種Cache都必須支持必定的Cache清理策略,否則數據會一直增加,內存確定是扛不住的。Guava Cache也提供了多種Cache清理策略:

2.1 過時、清理

Guava Cache採用基於容量、Soft引用、Weak引用的清理觸發條件,基於過時時間、權重來決定哪些數據優先清理,採用LRU算法來清理數據。

 

2.1.1 基於容量的清理觸發條件

若是你的cache數量不該該一直保持增加狀態,你須要設定總量來限定cache的容量。能夠經過CacheBuilder.maximumSize(long capacity)來限定。當容量即將達到上限時,會自動的進行數據清理。默認的最大容量是 1<<30,若是想要限定,只能設置比1<<30小的數。

       由於Guava Cache有默認容量,也就是最大容量的限制,因此任何一個Guava Cache都是有界cache,不會無限制的增長。

 

       在快要達到容量限定值開始清理數據時,採用的是LRU清理算法。與此同時,還能夠根據每個key-value的weight來控制清理,一個key-value的weight越低越容易被清除掉。默認狀況下,每個key-value的weight都是同樣的,即爲1。固然了你能夠自定義weight算法,經過CacheBuilder.weight(weight)便可。

 

其實嚴格來說,這個並不屬於

 

2.1.2 基於時間的過時方案

Guava Cache提供了兩種基於時間的數據過時方案:

1)     expireAfterWrite()

2)     expireAfterAccess()

 

根據訪問後的時間來控制數據是否過時。須要注意的是,設置了基於時間後,不會在內部另外啓動線程來定時清理掉過時的數據的。是依賴的與get請求,也就是說每一次訪問一個key時,會記錄時間,再一次訪問時,會先判斷數據是否過時了,一旦過時了,就清理掉,被清理掉後,下一次訪問時,會調用配置的CacheLoader進行加載。

 

當使用基於時間的過時策略時,能夠自定義本身的計時器的,使用CacheBuilder.ticker(ticker)便可。

 

須要說明的是,這裏的基於時間的過時策略是針對每個key-value的,若是你的業務中極有可能每個key-value都不同的話,就不適合使用了。若是你對業務中有能夠枚舉的幾個時間過時粒度,能夠建立多個Guava Cache來完成的。

 

2.1.3 基於Reference的Key、Value

能夠利用weak reference, soft reference來清理緩存。具體來講 weak reference 能夠用在key, value上;soft reference 能夠用在 value上。

 

 2.1.4 手動移除(顯示移除)

固然了,Guava Cache也提供了最基本的手動移除key-value的方案,直接從cache移除:

Cache.invalidate(key) 單個移除

Cache.invalidateAll(keys) 批量移除

Cache.invalidate() 移除全部

 

 2.2 RemoveListener

若是你的業務對數據的清理感興趣,還能夠指定RemoveListener的。

 

 2.3 數據清理時機

從上面的幾種清理策略或者過時策略來看,Guava Cache 提供的是被動清理方案,不管是基於容量、基於時間、基於Reference,它們都是被動的清理方案。而手動清理方案雖然是一種主動的清理方案,但它只是針對與你已經肯定了不會再用的數據。

 

       Cache.cleanUp() 是一種主動的清理方案,它會清理掉過時的數據。

 

 

三、refresh

LoadingCache中的refresh 提供了值替換的功能。在調用refresh時,會先調加載新值,新值加載到後替換掉老值,並返回老值。若是加載不到新值,老值是被保留的,不會被替換掉的。

 

LoadingCache是引起CacheLoader調用reload方法的,CacheLoader的reload返回的是ListenableFuture,也就代表了,支持同步reload,也支持異步的reload的。

 

 

四、配置說明

Guava Cache中的兩種cache(Cache,LoadingCache)的實現分別由LocalManuelCache、LocalLoadingCache來完成。建立這兩種cache也很簡單,使用CacheBuilder便可。在構建cache時,須要配置數據清理策略、併發級別等。

 

 

concurrencyLevel:底層的LocalCache 也是一個ConcurrentMap,它的實現與JDK8以前版本中的ConcurrentHashMap相似,也採用了多個segment來提升併發。他們均可以配置concurrencyLevel,來控制segment的數量,來提升併發。ConcurrentHashMap的默認值是16,最大值是1<<16;這裏的默認值是4,最大值爲 1<<16。

 

initialCapacity:初始容量配置,默認值是16.

maximumSize:最大容量。

maximumWeight:最大權重

 

keyEquivalence、valueEquivalence,用於指定內部判斷key,value時,是否同樣的算法。另外須要說明的是,默認狀況下Guava Cache內部判斷key, value是否相等時,針對不一樣的配置採用不一樣的方案的。若是啓用了weakKey,weakValue,softValue的狀況下,相應的key或者value的相等性判斷是採用的是 ==,若是沒有啓用weakKey,softValue,weakValue的狀況下,相應的key,value的相等性判斷使用是equals()。

 

 

五、場景說明

不適用於數據有不一樣的過時時間的場景。

相關文章
相關標籤/搜索