本地緩存之神-guava cache

背景

guava cache是google工具包中提供的關(guān)于本地緩存解決方案,提供了基于容量,時(shí)間和引用的緩存回收方式。
容量:利用LRU算法,
回收:Java虛擬機(jī)的垃圾回收機(jī)制(堆緩存)。

使用場(chǎng)景

愿意花費(fèi)一部分內(nèi)存來提高速度 -- 以空間換時(shí)間
期待有些關(guān)鍵字會(huì)被多次查詢 -- 熱點(diǎn)數(shù)據(jù)
緩存并不需要存儲(chǔ)比RAM中更多的數(shù)據(jù)。Guava caches是一次性運(yùn)行的本地緩存,并不會(huì)把數(shù)據(jù)存儲(chǔ)到文件中或者外部服務(wù)器上 -- 不能持久化

功能

創(chuàng)建本地緩存

a.CacheLoader

/**
 * CacheLoader 當(dāng)檢索不存在的時(shí)候,會(huì)自動(dòng)的加載信息的!
 */
private static LoadingCache<String, String> loadingCache = CacheBuilder
        .newBuilder()
        .maximumSize(2)
        .expireAfterWrite(10, TimeUnit.SECONDS)
        .concurrencyLevel(2)
        .recordStats()
        .build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                String value = map.get(key);
                log.info(" load value by key; key:{},value:{}", key, value);
                return value;
            }
        });

public static String getValue(String key) {
    try {
        return loadingCache.get(key);
    } catch (Exception e) {
        log.warn(" get key error ", e);
        return null;
    }
}

b.Callable

private static Cache<String, String> cacheCallable = CacheBuilder
        .newBuilder()
        .maximumSize(2)
        .expireAfterWrite(10, TimeUnit.SECONDS)
        .concurrencyLevel(2)
        .recordStats()
        .build();
/**
 * Callable 如果有緩存則返回;否則運(yùn)算、緩存、然后返回
 */
public static String getValue1(String key) {
    try {
         return cacheCallable.get(key, new Callable<String>() {
            @Override
            public String call() throws Exception {
                String value = map.get(key);
                log.info(" load value by key; key:{},value:{}", key, value);
                return value;
            }
        });
    } catch (Exception e) {
        log.warn(" get key error ", e);
        return null;
    }
}

顯示插入-顯示清除

public static void put(String key, String value){
    loadingCache.put(key,value); //手動(dòng)添加值
}

public static void remove(String key){
    loadingCache.invalidate(key); //移除一個(gè)
    loadingCache.invalidateAll(Lists.newArrayList(key)); // 批量移除
    loadingCache.invalidateAll(); // 移除全部-清空
}

移除監(jiān)聽器

a.同步

private static LoadingCache<String, String> loadingCache = CacheBuilder
        .newBuilder()
        .maximumSize(2)
        .expireAfterWrite(10, TimeUnit.SECONDS)
        .concurrencyLevel(2)
        .recordStats()
        .removalListener(new RemovalListener<String, String>() { // sync
            @Override
            public void onRemoval(RemovalNotification<String, String> removal) {
                // TODO remove notification
                log.info("loadingCache is removed. key:{},value:{}",removal.getKey(),removal.getValue());
            }
        })
        .build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                String value = map.get(key);
                log.info(" load value by key; key:{},value:{}", key, value);
                return value;
            }
        });

b.異步

// 創(chuàng)建一個(gè)監(jiān)聽器
private static class MyRemovalListener implements RemovalListener<String,String>{
    @Override
    public void onRemoval(RemovalNotification<String, String> removal) {
        // TODO remove notification
        log.info("loadingCache is removed. key:{},value:{}",removal.getKey(),removal.getValue());
    }
}

private static RemovalListener<String, String> async = RemovalListeners.asynchronous(new MyRemovalListener(), Executors.newSingleThreadExecutor());

private static Cache<String, String> cacheCallable = CacheBuilder
        .newBuilder()
        .maximumSize(2)
        .expireAfterWrite(10, TimeUnit.SECONDS)
        .concurrencyLevel(2)
        .recordStats()
        .removalListener(async)
        .build();

為什么使用異步,不需要解釋了吧!

統(tǒng)計(jì)

//先開啟統(tǒng)計(jì)
private static Cache<String, String> cacheCallable = CacheBuilder
        .newBuilder()
        .maximumSize(2)
        .expireAfterWrite(10, TimeUnit.SECONDS)
        .concurrencyLevel(2)
        .recordStats()
        .removalListener(async)
        .recordStats()//開啟統(tǒng)計(jì)
        .build();
//獲取統(tǒng)計(jì)信息
CacheStats stats = cacheCallable.stats();
>>
public final class CacheStats {
    private final long hitCount;
    private final long missCount;
    private final long loadSuccessCount;
    private final long loadExceptionCount;
    private final long totalLoadTime;
    private final long evictionCount;
...

緩存回收方式

a. 基于容量回收
maximumSize(long):當(dāng)緩存中的元素?cái)?shù)量超過指定值時(shí)。
b. 定時(shí)回收
expireAfterAccess(long, TimeUnit):緩存項(xiàng)在給定時(shí)間內(nèi)沒有被讀/寫訪問,則回收。請(qǐng)注意這種緩存的回收順序和基于大小回收一樣。
expireAfterWrite(long, TimeUnit):緩存項(xiàng)在給定時(shí)間內(nèi)沒有被寫訪問(創(chuàng)建或覆蓋),則回收。如果認(rèn)為緩存數(shù)據(jù)總是在固定時(shí)候后變得陳舊不可用,這種回收方式是可取的。
如下文所討論,定時(shí)回收周期性地在寫操作中執(zhí)行,偶爾在讀操作中執(zhí)行。
c. 基于引用回收(Reference-based Eviction)
CacheBuilder.weakKeys():使用弱引用存儲(chǔ)鍵。當(dāng)鍵沒有其它(強(qiáng)或軟)引用時(shí),緩存項(xiàng)可以被垃圾回收。
CacheBuilder.weakValues():使用弱引用存儲(chǔ)值。當(dāng)值沒有其它(強(qiáng)或軟)引用時(shí),緩存項(xiàng)可以被垃圾回收。
CacheBuilder.softValues():使用軟引用存儲(chǔ)值。軟引用只有在響應(yīng)內(nèi)存需要時(shí),才按照全局最近最少使用的順序回收。

優(yōu)點(diǎn)

線程安全的緩存,與ConcurrentMap相似,但前者增加了更多的元素失效策略,后者只能顯示的移除元素。
提供了三種基本的緩存回收方式:基于容量回收、定時(shí)回收和基于引用回收。定時(shí)回收有兩種:按照寫入時(shí)間,最早寫入的最先回收;按照訪問時(shí)間,最早訪問的最早回收。
監(jiān)控緩存加載/命中情況。
集成了多部操作,調(diào)用get方式,可以在未命中緩存的時(shí)候,從其他地方獲取數(shù)據(jù)源(DB,redis),并加載到緩存中。

缺點(diǎn)

Guava Cache的超時(shí)機(jī)制不是精確的;
不能持久化本地緩存;
受限于服務(wù)器的內(nèi)存。

總結(jié)

那話說回來了,為什么要使用本地緩存呢?比IO更高效,比分布式緩存更穩(wěn)定。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Guava Cache以下的特性: automatic loading of entries into the c...
    小鋤禾閱讀 8,737評(píng)論 2 11
  • Google Guava Cache是一種非常優(yōu)秀本地緩存解決方案,提供了基于容量,時(shí)間和引用的緩存回收方式?;?..
    Acamy丶閱讀 26,313評(píng)論 3 34
  • 1、簡介 線程安全 Guava Cache提供了一種把數(shù)據(jù)(key-value對(duì))緩存到本地(JVM)內(nèi)存中的機(jī)制...
    進(jìn)擊的小鹿閱讀 1,911評(píng)論 0 1
  • guava cache簡介 為什么會(huì)有g(shù)uava cache 實(shí)際開發(fā)中,有時(shí)候會(huì)有一些不常修改,但是經(jīng)常會(huì)被用到...
    黃二的NPE閱讀 943評(píng)論 0 2
  • 項(xiàng)目地址 EZLedView項(xiàng)目地址 效果圖a 原理 廣告牌中經(jīng)常能看到上面這種顯示效果,使用LED燈實(shí)現(xiàn)文字甚至...
    大飛機(jī)閱讀 6,014評(píng)論 2 34

友情鏈接更多精彩內(nèi)容