Guava Cache 与 ConcurrentMap 很相似,但也不完全一样。最基本的区别是:ConcurrentMap 会一直保存所有添加的元素,直到显式地移除。相对地,Guava Cache 为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管 LoadingCache 不回收元素,它也是很有用的,因为它会自动加载缓存。Guava Cache 是在内存中缓存数据,相比较于数据库或redis存储,访问内存中的数据会更加高效。
■ 本地缓存的应用场景: 对性能有非常高的要求 不经常变化 占用内存不大 有访问整个集合的需求 数据允许不时时一致
■ Guava Cache 的优势 缓存过期和淘汰机制 在GuavaCache中可以设置Key的过期时间,包括访问过期和创建过期 GuavaCache在缓存容量达到指定大小时,采用LRU的方式,将不常使用的键值从Cache中删除 并发处理能力 GuavaCache类似CurrentHashMap,是线程安全的。 提供了设置并发级别的api,使得缓存支持并发的写入和读取 采用分离锁机制,分离锁能够减小锁力度,提升并发能力 分离锁是分拆锁定,把一个集合看分成若干partition, 每个partiton一把锁。ConcurrentHashMap就是分了16个区域,这16个区域之间是可以并发的。GuavaCache采用Segment做分区。 更新锁定 一般情况下,在缓存中查询某个key,如果不存在,则查源数据,并回填缓存。(Cache Aside Pattern)在高并发下会出现,多次查源并重复回填缓存,可能会造成源的宕机(DB),性能下降 GuavaCache可以在CacheLoader的load方法中加以控制,对同一个key,只让一个请求去读源并回填缓存,其他请求阻塞等待。 集成数据源 一般我们在业务中操作缓存,都会操作缓存和数据源两部分GuavaCache的get可以集成数据源,在从缓存中读取不到时可以从数据源中读取数据并回填缓存 监控缓存加载/命中情况 统计
接口Cache代表一块缓存,它有如下方法
public interface Cache<K, V> {
V get(K key, Callable<? extends V> valueLoader) throws ExecutionException;
ImmutableMap<K, V> getAllPresent(Iterable<?> keys);
void put(K key, V value);
void putAll(Map<? extends K, ? extends V> m);
void invalidate(Object key);
void invalidateAll(Iterable<?> keys);
void invalidateAll();
long size();
CacheStats stats();
ConcurrentMap<K, V> asMap();
void cleanUp();
}
使用实例
GuavaCache有两种创建方式: CacheLoader和Callable callback
public class GuavaDemo {
public static void main(String args[]) throws Exception {
LoadingCache<String, Object> cache = CacheBuilder.newBuilder()
// 最大3个 //Cache中存储的对象,写入3秒后过期
.maximumSize(3).expireAfterWrite(3,
//记录命中率 失效通知
TimeUnit.SECONDS).recordStats().removalListener(new
RemovalListener<Object, Object>() {
public void onRemoval(RemovalNotification<Object, Object>
notification) {
System.out.println(notification.getKey() + ":" + notification.getCause());
}
}.build(
new CacheLoader<String, Object>() {
@Override
public String load(String s) throws Exception {
return Constants.hm.get(s);
}
}
);
/*
初始化cache
*/
initCache(cache);
System.out.println(cache.size());
displayCache(cache);
System.out.println("=============================");
Thread.sleep(1000);
System.out.println(cache.getIfPresent("1"));
Thread.sleep(2500);
System.out.println("=============================");
displayCache(cache);
}
public static Object get(String key, LoadingCache cache) throws Exception {
Object value = cache.get(key, new Callable() {
@Override
public Object call() throws Exception {
Object v = Constants.hm.get(key);
//设置回缓存
cache.put(key, v);
return v;
}
});
return value;
}
public static void initCache(LoadingCache cache) throws Exception {
/*
前三条记录
*/
for (int i = 1; i <= 3; i++) {
cache.get(String.valueOf(i));
}
}
/**
*获得当前缓存的记录
@param
cache
*@throws Exception
**/
public static void displayCache(LoadingCache cache) throws Exception {
Iterator its = cache.asMap().entrySet().iterator();
while (its.hasNext()) {
System.out.println(its.next().toString());
}
}
}
## CacheLoader
LoadingCache<String,String> cache = CacheBuilder.newBuilder()
.maximumSize(3)
.build(
new CacheLoader<String, String>() {
@Override
public String load(String s) throws Exception {
return Constants.hm.get(s);
}
}
);
## Callable Callback
public static Object get(String key,LoadingCache cache)throws Exception{
Object value=cache.get(key, new Callable() {
@Override
public Object call() throws Exception {
String v= Constants.hm.get(key);
//设置回缓存
cache.put(key,v);
return v;
}
});
return value;
}
■ GuavaCache的数据删除分为:被动删除和主动删除
//基于数据大小的删除
LoadingCache<String,Object> cache= CacheBuilder.newBuilder()
/*
加附加的功能
*/
//最大个数
.maximumSize(3)
.build(new CacheLoader<String, Object>() {
//读取数据源
@Override
public Object load(String key) throws Exception {
return Constants.hm.get(key);
}
});
//读取缓存中的1的数据 缓存有就读取 没有就返回null
System.out.println(cache.getIfPresent("5"));
//读取4 读源并回写缓存 淘汰一个(LRU+FIFO)
get("4",cache);
//缓存中的数据 如果3秒内没有访问则删除
.maximumSize(3).expireAfterAccess(3, TimeUnit.SECONDS)
。。。。
Thread.sleep(1000);
//访问1 1被访问
cache.getIfPresent("1");
//歇了2.1秒
Thread.sleep(2100);
//最后缓存中会留下1
System.out.println("==================================");
display(cache);
//基于引用的删除
LoadingCache<String,Object> cache = CacheBuilder.newBuilder()
// 最大3个 值的弱引用
.maximumSize(3).weakValues()
.build();
Object value = new Object();
cache.put("1",value);
value = new Object();//原对象不再有强引用
//强制垃圾回收
System.gc();
System.out.println(cache.getIfPresent("1"));
////将key=1 删除
cache.invalidate("1");
//将key=1和2的删除
cache.invalidateAll(Arrays.asList("1","2"));
//清空缓存
cache.invalidateAll();
查看文档 http://www.ibloger.net/article/3345.html