介绍
Guava Cache是Google出品的一个本地缓存,使用CacheBuilder创建。它与ConcurrentMap很相似,都是线程安全的。但Guava Cache有一套超时机制,会自动将超时的缓存失效,从而节省内存。
两种创建方式
CacheLoader
根据key加载值
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(new CacheLoader<String, String>() {
@Override
public String load(String s) throws Exception {
s = "hello " + s;
return s;
}
});
System.out.println(cache.get("mike"));
Callable
获取默认值
Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterAccess(10, TimeUnit.MINUTES)
.build();
String value = cache.get("mike", () -> "default value");
System.out.println(value);
三种清理缓存的方式
- expireAfterAccess: 当缓存项在指定的时间段内没有被读或写就会被回收。
- expireAfterWrite:当缓存项在指定的时间段内没有更新就会被回收。
- refreshAfterWrite:当缓存项上一次更新操作之后的多久会被刷新。
在缓存失效时,guava cache会严格限制只有1个加载操作,获得锁的线程去加载数据,其余线程阻塞,直到数据加载完成,其余线程再逐一获得锁,再获取数据。这样会很好地防止缓存失效的瞬间大量请求穿透到后端引起雪崩效应。
refreshAfterWrite不同,它也会严格限制只有1个加载操作,但其余线程不会阻塞,而是会获取到旧值返回。可以有效减少等待和抢锁的开销、所以refreshAfterWrite的性能更好。缺点是缓存失效时间不精确,缓存失效后仍可能获取到旧值。
expire和refresh方式可以一起使用。