Guava缓冲管理器分类使用说明
【模板】:
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.removalListener(MY_LISTENER)
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
return createExpensiveGraph(key);
}
});
【用于】:
计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存。(1)愿意消耗一些内存空间来提升速度;(2)预料到某些键会被查询一次以上;(3)缓存中存放的数据总量不会超出内存容量。(Guava Cache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。如果这不符合你的需求,请尝试Memcached这类工具)
【加载】:
为保证缓存内容的一致性,应该在调用get时传入一个Callable实例,保留“获取缓存-如果没有-则计算[get-if-absent-compute]”的原子语义。
【From a CacheLoader】
【方式一】:LoadingCache.get(K)声明为抛出ExecutionException异常 注意:声明异常不能使用getUnchecked(K)查找缓存
LoadingCache是附带CacheLoader构建而成的缓存实现,创建自己的CacheLoader通常只需要简单地实现V load(K key) throws Exception方法(这个方法要么返回已缓存的值,要么使用CacheLoade
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumSize(1000)
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
return createExpensiveGraph(key);
}
});
...
try {
return graphs.get(key);
} catch (ExecutionException e) {
throw new OtherException(e.getCause());
}
r向缓存原子地加载新值。)
【方式二】:定义的CacheLoader没有声明任何检查型异常
使用getUnchecked() 方法,如果对应值不存在,则计算并缓存值到缓存中, Tips : 批量查询可以使用getAll(Iterable<? extends K>)方法。
LoadingCache<Key,Graph> graphs =CacheBuilder.newBuilder()
.expireAfterAccess(10,TimeUnit.MINUTES)
.build(
newCacheLoader<Key,Graph>(){
publicGraph load(Key key){// no checked exception
return createExpensiveGraph(key);
}
});
...
return graphs.getUnchecked(key);
- 【From a Callable】 所有Guava缓存,不论是否会自动加载,都支持get(K, Callable(V))方法
当给定键的缓存值已存在时则直接返回,否则通过指定的Callable方法进行计算并将值存放到缓存中。直到加载完成时,相应的缓存才会被更改。该方法简单实现了"if cached, return; otherwise create, cache and return"语义。
Cache<Key,Value> cache =CacheBuilder.newBuilder()
.maximumSize(1000)
.build();// look Ma, no CacheLoader
...
try{
// If the key wasn't in the "easy to compute" group, we need to
// do things the hard way.
cache.get(key,newCallable<Value>(){
@Override
publicValue call()throwsAnyException{
return doThingsTheHardWay(key);
}
});
}catch(ExecutionException e){
thrownewOtherException(e.getCause());
}
【注意】——> 当使用CacheLoader或Callable来加载缓存时,应该优先使用Cache.get(K, Callable<V>),而不是Cache.asMap().putIfAbsent (asMap中的任何方法都不能自动的将数据加载到缓存中)
【缓存回收】:
【缓存值不再值得保留】:(1)基于容量回收策略;(2)基于时间回收策略;(3)基于引用回收策略
【基于容量回收策略】 :
LoadingCache<Key,Graph> graphs =CacheBuilder.newBuilder()
.maximumWeight(100000)
.weigher(
newWeigher<Key,Graph>(){
publicint weigh(Key k,Graph g){
return g.vertices().size();
}
})
.build(
newCacheLoader<Key,Graph>(){
publicGraph load(Key key){// no checked exception
return createExpensiveGraph(key);
}
});
基于时间回收策略:(定时回收)
CacheBuilder为基于时间的回收提供了两种方式:(定时过期回收会在写的过程中周期执行,偶尔也会读的过程中执行)
- expireAfterAccess(long, TimeUnit) 当缓存项在指定的时间段内没有被读或写就会被回收。这种回收策略类似于基于容量回收策略;
- expireAfterWrite(long, TimeUnit) 当缓存项在指定的时间段内没有更新就会被回收。如果我们认为缓存数据在一段时间后数据不再可用,那么可以使用该种策略。
基于引用回收策略:(定时回收)
- CacheBuilder.weakKeys() 使用弱引用存储键。当没有(强或软)引用到该键时,相应的缓存项将可以被垃圾回收。由于垃圾回收是依赖==进行判断,因此这样会导致整个缓存也会使用==来比较键的相等性,而不是使用equals();
- CacheBuilder.weakValues() 使用弱引用存储缓存值。当没有(强或软)引用到该缓存项时,将可以被垃圾回收。由于垃圾回收是依赖==进行判断,因此这样会导致整个缓存也会使用==来比较缓存值的相等性,而不是使用equals();
- CacheBuilder.softValues() 使用软引用存储缓存值。当响应需要时,软引用才会被垃圾回收通过最少使用原则回收掉。由于使用软引用造成性能上的影响,我们强烈建议使用可被预言的maximum cache size的策略来代替。同样使用softValues()缓存值的比较也是使用==,而不是equals()。
【移除监听器】
【参考文献】:Guava 驱逐策略、弱引用键、缓存值软引用、刷新缓存、删除通知