Caches在很多情况下非常有用,比如,当一个值在计算和获取时很消耗时间
就可以通过caches来解决,你需要在特定的地方多次使用它。
Cache像一个ConcurrentMap,但不是完全相同,最不同的地方时ConcurrentMap
持久化所有加入的元素,直到明确被移除
而cache在到达内存限制时,自动回收对象。在一些情况下LoadingCache自动加载缓存,使得其更有用
Guava很有用:
1 使用内存加速
2. 一些值需要多次使用
3.适合数据只保存内存中使用(不适合数据太多)
通过CacheBuilder去获取一个Cache
LoadingCache
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);
}
}
);
...
try{
return graphs.get(key);
}catch(ExecutionException e){
throw new OtherException(e.getCause());
}
同时支持批量的操作,CacheLoader.getAll()
通过Callable<V>获取,支持get(K,Callable<V>),这个方法返回和key相关的值
如果缓存中存在这样的值,返回,不存在则创建,加入缓存,并返回值
Cache<Key, Value> cache = CacheBuilder.newBuilder().maximumSize(1000)
.build();
try {
cache.get(key, new Callable<Value>) () {
public Value call () throws AnyException {
return doThingsTheHardWay(key);
}
});
} catch (ExecutionException e) {
throw new OtherException(e.getCause());
}
直接插入操作
通过cache.put(key,value)将值直接放入缓存,这样覆盖了以前缓存中
存在的相关值
收回
现实是我们没有足够的内存存储所有的值,我们需要考虑
什么情况下没有必要继续存储这个值,guava cache中提供了三种回收方法
基于大小
使用方法CacheBuilder.maxinumSize(long)设置缓存最大的限制
如果超过了限制,将会回收不经常使用的数据
基于时间
CacheBuilder提供了两种基于时间方法
expireAfterAccess(long,TimeUnit) 在指定时间内实体没有被访问或者修改,将会被回收
保证小于指定的缓存大小限制
expireAfterwrite(long,TimeUnit) 在指定时间内实体没有被创建或者值没有被替换
基于引用
guava允许设置缓存允许垃圾回收,使用在key或者values上弱引用
使用在值上软引用
CacheBuilder.weakKeys() s使用弱引用存储keys,这样实体允许在没有强或弱引用的时候垃圾回收;
CacheBuilder.weakBValues()使用弱引用存储值values,这样在没有强或者弱引用的情况下,进行垃圾回收
CacheBuilder.softValues() 使用软引用包装数据,软引用对象通过最近最少使用算法进行垃圾回收
明确迁移
在任何时候,都是明确失效而不是等待实体被回收
Removal Listeners
可以指定实体移除时候的特定的移除监听器
CacheBuilder.removalListener(RemovalListener)
/**
* 创建缓存
* @return
*/
public Cache<String, String> getCache() {
CacheLoader<String, String> loader = new CacheLoader<String, String>() {
public String load(String s) throws Exception {
return null;
}
};
RemovalListener<String, String> removalListener = new RemovalListener<String, String>() {
public void onRemoval(RemovalNotification<String, String> removalNotification) {
System.out.println("remove info ...");
}
};
return CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.MINUTES)
.removalListener(removalListener)
.build(loader);
}