內容摘要算法
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)。併發
除了上面的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清理策略:
Guava Cache採用基於容量、Soft引用、Weak引用的清理觸發條件,基於過時時間、權重來決定哪些數據優先清理,採用LRU算法來清理數據。
若是你的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)便可。
其實嚴格來說,這個並不屬於
Guava Cache提供了兩種基於時間的數據過時方案:
1) expireAfterWrite()
2) expireAfterAccess()
根據訪問後的時間來控制數據是否過時。須要注意的是,設置了基於時間後,不會在內部另外啓動線程來定時清理掉過時的數據的。是依賴的與get請求,也就是說每一次訪問一個key時,會記錄時間,再一次訪問時,會先判斷數據是否過時了,一旦過時了,就清理掉,被清理掉後,下一次訪問時,會調用配置的CacheLoader進行加載。
當使用基於時間的過時策略時,能夠自定義本身的計時器的,使用CacheBuilder.ticker(ticker)便可。
須要說明的是,這裏的基於時間的過時策略是針對每個key-value的,若是你的業務中極有可能每個key-value都不同的話,就不適合使用了。若是你對業務中有能夠枚舉的幾個時間過時粒度,能夠建立多個Guava Cache來完成的。
能夠利用weak reference, soft reference來清理緩存。具體來講 weak reference 能夠用在key, value上;soft reference 能夠用在 value上。
固然了,Guava Cache也提供了最基本的手動移除key-value的方案,直接從cache移除:
Cache.invalidate(key) 單個移除
Cache.invalidateAll(keys) 批量移除
Cache.invalidate() 移除全部
若是你的業務對數據的清理感興趣,還能夠指定RemoveListener的。
從上面的幾種清理策略或者過時策略來看,Guava Cache 提供的是被動清理方案,不管是基於容量、基於時間、基於Reference,它們都是被動的清理方案。而手動清理方案雖然是一種主動的清理方案,但它只是針對與你已經肯定了不會再用的數據。
Cache.cleanUp() 是一種主動的清理方案,它會清理掉過時的數據。
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()。
不適用於數據有不一樣的過時時間的場景。