您好,登錄后才能下訂單哦!
本篇內容主要講解“Guava cache如何構建無阻塞緩存”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Guava cache如何構建無阻塞緩存”吧!
guava cache是本地緩存,基于JDK ConcurrentHashMap 實現。不適合分布式環境使用(除非可以保證其節點緩存一致性如: 開源中國社區開源的 J2cache)。如果使用場景簡單,沒必要使用到緩存復雜特性可以使用ConcurrentHashMap ,比Guava cache 更高效直接。
構建方式有三種:CacheLoader,Callable,Inserted Directly。
CacheLoader:
適用于有一些合理的默認函數來加載或計算與密鑰相關的值
Callable:
如果需要覆蓋默認值,但仍需要原子“get-if-absent-compute”語義,則應使用get方法傳遞Callable接口。實現了:如果已緩存,返回;否則創建,緩存和返回。
Inserted Directly:
使用put方式直接插入值。
/** 自定義刷新緩存線程池 */
private static ListeningExecutorService backgroundRefreshPools =
MoreExecutors.listeningDecorator(executorService);
/** 創建緩存 */
public static final LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.refreshAfterWrite(100,TimeUnit.MILLISECONDS)
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) {
return getNewValue();
}
@Override
public ListenableFuture<String> reload(String key,String oldValue) {
return backgroundRefreshPools.submit(ReloadCache::getNewValue);
}
});
源碼:
public ListenableFuture<V> loadFuture(K key, CacheLoader<? super K, V> loader) {
try {
stopwatch.start();
V previousValue = oldValue.get();
// 獲取值為空時 加載load方法
if (previousValue == null) {
V newValue = loader.load(key);
return set(newValue) ? futureValue : Futures.immediateFuture(newValue);
}
// 否則執行reload
ListenableFuture<V> newValue = loader.reload(key, previousValue);
if (newValue == null) {
return Futures.immediateFuture(null);
}
return transform(
newValue,
new com.google.common.base.Function<V, V>() {
@Override
public V apply(V newValue) {
LoadingValueReference.this.set(newValue);
return newValue;
}
},
directExecutor());
} catch (Throwable t) {
ListenableFuture<V> result = setException(t) ? futureValue : fullyFailedFuture(t);
if (t instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
return result;
}
}
當CacheBuilder.refreshAfterWrite(java.time.Duration)或通過調用LoadingCache.refresh(K)刷新現有緩存條目時,將調用此方法。
@GwtIncompatible
public ListenableFuture<V> reload(K key, V oldValue)throws Exception
參數:
key - 應該加載其值的非null鍵
oldValue - 與key對應的非null舊值
返回值:
不為null的ListenableFuture,不會返回null
異常:
Exception - 如果無法重新加載結果
注意事項:
1、refresh 會“吞掉”緩存更新時的異常操作。依然使用舊值返回。
2、可以使用CacheBuilder.refreshAfterWrite(long,TimeUnit)將自動定時刷新添加到緩存中。
與expireAfterWrite相反,refreshAfterWrite將使鍵在指定的持續時間后符合刷新條件,但只有在查詢條目時才會實際刷新。
(如果將CacheLoader.reload實現為異步,則刷新不會減慢查詢速度。)因此,例如,您可以在同一緩存上指定refreshAfterWrite和expireAfterWrite,以便條目上的到期計時器不會每當條目符合刷新條件時,都會盲目重置,因此如果條目在符合刷新條件后未被查詢,則允許條目過期。expireAfterWrite 和 refreshAfterWrite 不建議一起使用。
3、refreshAfterWrite 構建緩存更適合應對,熱點緩存問題。由于總有舊值返回是一種托底方案。
4、guava cache 刷新功能很多基于其并發工具類Futures提供的線程回調功能。
當沒有guava cache 對緩存可使用 ScheduledThreadPoolExecutor + ConcurrentHashMap
注意:對異常的處理,否則導致線程的終止。
參考資料:guava cache wiki https://github.com/google/guava/wiki/CachesExplained
guava cache api docs https://google.github.io/guava/releases/snapshot-jre/api/docs/
到此,相信大家對“Guava cache如何構建無阻塞緩存”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。