-
適用性
緩存在很多情況下都是非常有用的惠险。比如诡蜓,我們需要多次根據(jù)給定的輸入獲取值诽表,而且該值計算或者獲取的開銷是非常昂貴的起趾。
緩存和ConcurrentMap是非常相像的诗舰,但是它們也不完全一樣。最根本的區(qū)別就是阳掐,ConcurrentMap會持有所有添加的對象始衅,直到被顯示的移除。而緩存為了限制其內存的使用缭保,通常都會配置成可以自動的將對象移除。在某些情況下即使不自動移除對象也是非常有用的蝙茶,如LoadingCache它會自動加載緩存對象艺骂。
一般,Guava緩存適用于以下幾種情況:- 你愿意花費一些內存來換取性能提升隆夯;
- 你預測到某些鍵會多次進行查詢钳恕;
- 你的緩存數(shù)據(jù)不超過內存(Guava緩存是單個應用中的本地緩存。它不會將數(shù)據(jù)存儲到文件中蹄衷,或者外部服務器忧额。如果不適合你,可以考慮一下 Memcached)愧口。
如果你的需要符合上面所說的每一條睦番,那么選擇Guava緩存絕對沒錯。
-
創(chuàng)建guava cache
對于緩存首先需要明確的是:有沒有一個方法可以通過給定的鍵來計算/加載相應的值?如果有托嚣,那么可以使用CacheLoader巩检。如果沒有這樣的方法,或者你想復寫緩存的加載方式示启,但你仍想保留“get-if-absent-compute”語義兢哭,你可以在調用get方法時傳入一個Callable實例,來達到目的夫嗓。緩存的對象可以通過Cache.put直接插入迟螺,但是自動加載是首選,因為自動加載可以更加容易的判斷所有緩存信息的一致性舍咖。
Guava Cache有兩種創(chuàng)建方式:- cacheLoader
- callable callback
-
LoadingCache 緩存是通過一個CacheLoader來構建緩存矩父。創(chuàng)建一個CacheLoader僅需要實現(xiàn)V load(K key) throws Exception方法即可。下面的范例就是如何創(chuàng)建一個LoadingCache谎仲。
LoadingCache<Key,Graph> graphs =CacheBuilder.newBuilder() .maximumSize(1000) .build( newCacheLoader<Key,Graph>(){ publicGraph load(Key key)throwsAnyException{ return createExpensiveGraph(key); } }); try{ return graphs.get(key);
}catch(ExecutionException e){ thrownewOtherException(e.getCause()); }
-
callable callback的實現(xiàn):
Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000).build(); String resultVal = cache.get("jerry", new Callable<String>() { public String call() { String strProValue="hello "+"jerry"+"!"; return strProValue; } }); System.out.println("jerry value : " + resultVal); resultVal = cache.get("peida", new Callable<String>() { public String call() { String strProValue="hello "+"peida"+"!"; return strProValue; } }); System.out.println("peida value : " + resultVal);
guava Cache數(shù)據(jù)移除:
guava做cache時候數(shù)據(jù)的移除方式浙垫,在guava中數(shù)據(jù)的移除分為被動移除和主動移除兩種。
被動移除數(shù)據(jù)的方式郑诺,guava默認提供了三種方式:
1. 基于大小的移除:看字面意思就知道就是按照緩存的大小來移除夹姥,如果即將到達指定的大小,那就會把不常用的鍵值對從cache中移除辙诞。
定義的方式一般為 CacheBuilder.maximumSize(long)辙售,還有一種一種可以算權重的方法,個人認為實際使用中不太用到飞涂。就這個常用的來看有幾個注意點旦部,
其一,這個size指的是cache中的條目數(shù)较店,不是內存大小或是其他士八;
其二,并不是完全到了指定的size系統(tǒng)才開始移除不常用的數(shù)據(jù)的梁呈,而是接近這個size的時候系統(tǒng)就會開始做移除的動作婚度;
其三,如果一個鍵值對已經(jīng)從緩存中被移除了官卡,你再次請求訪問的時候蝗茁,如果cachebuild是使用cacheloader方式的,那依然還是會從cacheloader中再取一次值寻咒,如果這樣還沒有哮翘,就會拋出異常
2. 基于時間的移除:guava提供了兩個基于時間移除的方法
expireAfterAccess(long, TimeUnit) 這個方法是根據(jù)某個鍵值對最后一次訪問之后多少時間后移除
expireAfterWrite(long, TimeUnit) 這個方法是根據(jù)某個鍵值對被創(chuàng)建或值被替換后多少時間移除
3. 基于引用的移除:
這種移除方式主要是基于java的垃圾回收機制,根據(jù)鍵或者值的引用關系決定移除
主動移除數(shù)據(jù)方式毛秘,主動移除有三種方法:
1.單獨移除用 Cache.invalidate(key)
2.批量移除用 Cache.invalidateAll(keys)
3.移除所有用 Cache.invalidateAll()
如果需要在移除數(shù)據(jù)的時候有所動作還可以定義Removal Listener饭寺,但是有點需要注意的是默認Removal Listener中的行為是和移除動作同步執(zhí)行的,如果需要改成異步形式,可以考慮使用RemovalListeners.asynchronous(RemovalListener, Executor) (******)