Guava介紹
Guava是一種基於開源的Java庫,其中包含谷歌正在由他們很多項目使用的很多核心庫。
這個庫是為了方便編碼,並減少編碼錯誤。
這個庫提供用於集合,緩存,支持原語,並發性,常見注解,字符串處理,I/O和驗證的實用方法。
Guava Cache適用場景
1 消耗一些內存空間來提升速度;
2 緩存中存放的數據總量不會超出內存容量。
(Guava Cache是單個應用運行時的本地緩存,不把數據存放到文件或外部服務器(Memcached, Redis))
Guava Cache介紹
數據結構:ConcurrentHash (The returned cache is implemented as a hash table with similar performance characteristics to ConcurrentHashMap.)
主要特性(詳見下面的相關鏈接):
1 自動加載
2 回收策略:
2.1 基於容量
2.2 基於存活時間
2.3 基於權重
2.4 基於引用
3 移除監聽器
4 緩存訪問統計
主要接口:CacheBuilder, LoadingCache, CacheStats
使用示例:
public class CacheProTest {
LoadingCache<Long, Person> cache;
private int cacheTimeoutSeconds = 10; // 10秒
Integer counter = 1;
@Before
public void initialize() {
System.out.println("初始化");
cache = CacheBuilder.newBuilder()
/* 回收策略:基於容量(least-recently-used eviction when a maximum size is exceeded) */
.maximumSize(10)
// .initialCapacity(initialCapacity)
/* 回收策略:基於存活時間(time-based expiration of entries, measured since last access or last write) */
.expireAfterWrite(cacheTimeoutSeconds, TimeUnit.SECONDS)
// .expireAfterAccess(duration, unit)
// .refreshAfterWrite(duration, unit)
/* 回收策略:基於權重 */
// .maximumWeight(maximumWeight)
// .weigher(weigher)
/* 回收策略:基於引用(keys automatically wrapped in weak references, values automatically wrapped in weak or soft references)*/
// .weakKeys()
// .weakValues()
// .softValues()
// 設置並發數為5,即同一時間最多只能有5個線程往cache執行寫入操作
// .concurrencyLevel(concurrencyLevel)
/* 緩存訪問統計(accumulation of cache access statistics) */
.recordStats()
/* 移除監聽器(notification of evicted (or otherwise removed) entries) */
// .removalListener(listener)
.build(new CacheLoader<Long, Person>() {
/* 自動加載(automatic loading of entries into the cache) */
@Override
public Person load(Long id) throws Exception {
System.out.println("獲取值, id=" + id);
// 調用接口獲取值
Person p = new Person();
p.setId(id);
p.setName("name" + counter.toString());
counter++;
return p;
}
});
}
@Test
public void test1() {
try {
/* 獲值 */
// ConcurrentMap<Long, Person> asMap = cache.asMap();
// cache.get(key); //
// cache.getAll(keys);
// cache.getIfPresent(key);
// cache.getAllPresent(keys);
// cache.size();
/* 存值 */
// cache.put(key, value);
// cache.putAll(m); // Map<? extends K, ? extends V> m
/* 移除/刪除 */
// cache.refresh(key);
// cache.invalidate(key);
// cache.invalidateAll();
// cache.invalidateAll(keys);
// cache.cleanUp();
/* 緩存訪問統計 */
CacheStats stats = cache.stats();
stats.averageLoadPenalty();
stats.evictionCount();
stats.hitCount();
stats.hitRate();
stats.loadCount();
stats.loadExceptionCount();
stats.loadExceptionRate();
stats.loadSuccessCount();
stats.missCount();
stats.missRate();
stats.requestCount();
stats.totalLoadTime();
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void test2() {
try {
Long id = 1L;
Person person1 = cache.get(id);
Thread.sleep(3L * 1000L);
Person person2 = cache.get(id);
Thread.sleep(11L * 1000L);
Person person3 = cache.get(id);
System.out.println(person1);
System.out.println(person2);
System.out.println(person3);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
Guava Cache使用時需要關注的點
1 了解LoadingCache.refresh
正如LoadingCache.refresh(K)所聲明,刷新表示為鍵加載新值,這個過程可以是異步的。
在刷新操作進行時,緩存仍然可以向其他線程返回舊值,而不像回收操作,讀緩存的線程必須等待新值加載完成。
如果刷新過程拋出異常,緩存將保留舊值,而異常會在記錄到日志后被丟棄[swallowed]。
重載CacheLoader.reload(K, V)可以擴展刷新時的行為,這個方法允許開發者在計算新值時使用舊的值。
2 了解 清理時機
使用CacheBuilder構建的緩存不會"自動"執行清理和回收工作,也不會在某個緩存項過期后馬上清理,也沒有諸如此類的清理機制。
它會在寫操作時順帶做少量的維護工作,或者偶爾在讀操作時做——如果寫操作實在太少的話。
因此使用LoadingCache.size() 一定要關注這個點。
相關鏈接
