緩存的主要作用是暫時在記憶體中儲存業務系統的資料處理結果,并且等待下次通路使用。在日常開發的很多場合,由于受限于硬碟IO的性能或者我們自身業務系統的資料處理和擷取可能非常費時,當我們發現我們的系統這個資料請求量很大的時候,頻繁的IO和頻繁的邏輯處理會導緻硬碟和CPU資源的瓶頸出現。緩存的作用就是将這些來自不易的資料儲存在記憶體中,當有其他線程或者用戶端需要查詢相同的資料資源時,直接從緩存的記憶體塊中傳回資料,這樣不但可以提高系統的響應時間,同時也可以節省對這些資料的處理流程的資源消耗,整體上來說,系統性能會有大大的提升
Guava中Cache的兩種建立方式
在Guava中可以通過cacheLoader和callable callback兩種方式來建立緩存。通過這兩種方法建立的cache,和通常用map來緩存的做法比,不同在于,這兩種方法都實作了一種邏輯——從緩存中取key X的值,如果該值已經緩存過了,則傳回緩存中的值,如果沒有緩存過,可以通過某個方法來擷取這個值。但不同的在于cacheloader的定義比較寬泛,是針對整個cache定義的,可以認為是統一的根據key值load value的方法。而callable的方式較為靈活,允許你在get的時候指定。
cacheLoader方式
測試代碼
@Test
public void testLoadingCache() throws Exception {
LoadingCache<String, String> cahceBuilder = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
System.out.println("請求的key為" + key + "在緩存中不存在,通過load方法擷取key.");
String strProValue = "hello " + key + "!";
return strProValue;
}
});
// 第一次到緩存裡面key為peida的資料,緩存不存在通過,load加載,并儲存到緩存裡面
System.out.println("a value:" + cahceBuilder.get("a"));
// 第二次擷取key為peida的資料,緩存已經存在,直接在緩存裡面傳回
System.out.println("a value:" + cahceBuilder.get("a"));
// 往緩存裡面存放資料
cahceBuilder.put("b", "bbbb");
// 緩存已經存在資料了,直接擷取
System.out.println("b value:" + cahceBuilder.get("b"));
}
輸出結果
請求的key為a在緩存中不存在,通過load方法擷取key.
a value:hello a!
a value:hello a!
b value:bbbb
callable callback方式
測試代碼
@Test
public void testcallableCache() throws Exception {
Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize().build();
String resultVal = cache.get("a", new Callable<String>() {
public String call() {
String strProValue = "hello " + "a" + "!";
return strProValue;
}
});
System.out.println("a value : " + resultVal);
resultVal = cache.getIfPresent("b");
System.out.println("a value : " + resultVal);
}
輸出結果
a value : hello a!
a value : null
cache的參數說明
回收的參數:
1. 大小的設定:CacheBuilder.maximumSize(long) CacheBuilder.weigher(Weigher) CacheBuilder.maxumumWeigher(long)
2. 時間:expireAfterAccess(long, TimeUnit) expireAfterWrite(long, TimeUnit)
3. 引用:CacheBuilder.weakKeys() CacheBuilder.weakValues() CacheBuilder.softValues()
4. 明确的删除:invalidate(key) invalidateAll(keys) invalidateAll()
5. 删除監聽器:CacheBuilder.removalListener(RemovalListener)
refresh機制:
1. LoadingCache.refresh(K) 在生成新的value的時候,舊的value依然會被使用。
2. CacheLoader.reload(K, V) 生成新的value過程中允許使用舊的value
3. CacheBuilder.refreshAfterWrite(long, TimeUnit) 自動重新整理cache
guava Cache資料移除
guava做cache時候資料的移除方式,在guava中資料的移除分為被動移除和主動移除兩種。
被動移除資料的方式,guava預設提供了三種方式:
1.基于大小的移除:看字面意思就知道就是按照緩存的大小來移除,如果即将到達指定的大小,那就會把不常用的鍵值對從cache中移除。
定義的方式一般為 CacheBuilder.maximumSize(long),還有一種一種可以算權重的方法,個人認為實際使用中不太用到。就這個常用的來看有幾個注意點,
其一,這個size指的是cache中的條目數,不是記憶體大小或是其他;
其二,并不是完全到了指定的size系統才開始移除不常用的資料的,而是接近這個size的時候系統就會開始做移除的動作;
其三,如果一個鍵值對已經從緩存中被移除了,你再次請求通路的時候,如果cachebuild是使用cacheloader方式的,那依然還是會從cacheloader中再取一次值,如果這樣還沒有,就會抛出異常
2.基于時間的移除:guava提供了兩個基于時間移除的方法
expireAfterAccess(long, TimeUnit) 這個方法是根據某個鍵值對最後一次通路之後多少時間後移除
expireAfterWrite(long, TimeUnit) 這個方法是根據某個鍵值對被建立或值被替換後多少時間移除
3.基于引用的移除:
這種移除方式主要是基于java的垃圾回收機制,根據鍵或者值的引用關系決定移除
主動移除資料方式,主動移除有三種方法:
1.單獨移除用 Cache.invalidate(key)
2.批量移除用 Cache.invalidateAll(keys)
3.移除所有用 Cache.invalidateAll()
如果需要在移除資料的時候有所動作還可以定義Removal Listener,但是有點需要注意的是預設Removal Listener中的行為是和移除動作同步執行的,如果需要改成異步形式,可以考慮使用RemovalListeners.asynchronous(RemovalListener, Executor)