溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Guava cache如何構(gòu)建無阻塞緩存

發(fā)布時間:2021-07-07 16:44:17 來源:億速云 閱讀:197 作者:chen 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“Guava cache如何構(gòu)建無阻塞緩存”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“Guava cache如何構(gòu)建無阻塞緩存”吧!

Guava cache 構(gòu)建無阻塞緩存

適用場景:

guava cache是本地緩存,基于JDK ConcurrentHashMap 實現(xiàn)。不適合分布式環(huán)境使用(除非可以保證其節(jié)點緩存一致性如: 開源中國社區(qū)開源的 J2cache)。如果使用場景簡單,沒必要使用到緩存復(fù)雜特性可以使用ConcurrentHashMap ,比Guava cache 更高效直接。

構(gòu)建方式:

構(gòu)建方式有三種:CacheLoader,Callable,Inserted Directly。

CacheLoader:

適用于有一些合理的默認函數(shù)來加載或計算與密鑰相關(guān)的值

Callable:

如果需要覆蓋默認值,但仍需要原子“get-if-absent-compute”語義,則應(yīng)使用get方法傳遞Callable接口。實現(xiàn)了:如果已緩存,返回;否則創(chuàng)建,緩存和返回。

Inserted Directly:

使用put方式直接插入值。

CacheLoader構(gòu)建無阻塞緩存:

/** 自定義刷新緩存線程池 */

private static ListeningExecutorService backgroundRefreshPools =

MoreExecutors.listeningDecorator(executorService);

/** 創(chuàng)建緩存 */

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);

}

// 否則執(zhí)行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;

}

}

reload java doc

當(dāng)CacheBuilder.refreshAfterWrite(java.time.Duration)或通過調(diào)用LoadingCache.refresh(K)刷新現(xiàn)有緩存條目時,將調(diào)用此方法。

@GwtIncompatible

public ListenableFuture<V> reload(K key, V oldValue)throws Exception

參數(shù):

key - 應(yīng)該加載其值的非null鍵

oldValue - 與key對應(yīng)的非null舊值

返回值:

不為null的ListenableFuture,不會返回null

異常:

Exception - 如果無法重新加載結(jié)果

注意事項:

1、refresh 會“吞掉”緩存更新時的異常操作。依然使用舊值返回。

2、可以使用CacheBuilder.refreshAfterWrite(long,TimeUnit)將自動定時刷新添加到緩存中。

與expireAfterWrite相反,refreshAfterWrite將使鍵在指定的持續(xù)時間后符合刷新條件,但只有在查詢條目時才會實際刷新。

(如果將CacheLoader.reload實現(xiàn)為異步,則刷新不會減慢查詢速度。)因此,例如,您可以在同一緩存上指定refreshAfterWrite和expireAfterWrite,以便條目上的到期計時器不會每當(dāng)條目符合刷新條件時,都會盲目重置,因此如果條目在符合刷新條件后未被查詢,則允許條目過期。expireAfterWrite 和 refreshAfterWrite 不建議一起使用。

3、refreshAfterWrite 構(gòu)建緩存更適合應(yīng)對,熱點緩存問題。由于總有舊值返回是一種托底方案。

4、guava cache 刷新功能很多基于其并發(fā)工具類Futures提供的線程回調(diào)功能。

自定義構(gòu)建無阻塞緩存:

當(dāng)沒有g(shù)uava cache 對緩存可使用 ScheduledThreadPoolExecutor + ConcurrentHashMap

注意:對異常的處理,否則導(dǎo)致線程的終止。

參考資料: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如何構(gòu)建無阻塞緩存”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI