摘要:本文先介绍为什么使用 Guava Cache 缓存;然后讲解 Guava 缓存使用方法、清理方法及使用过程中踩过的坑;接着讲解其底层数据结构,分析其性能优异的原因;最后讲解在使用本地缓存时可以优化的方向。
为什么使用本地缓存
在多线程高并发场景中往往是离不开 cache 的,需要根据不同的应用场景来需要选择不同的 cache,比如分布式缓存如 Redis、memcached,还有本地(进程内)缓存如 ehcache、Guava Cache。缓存相比IO操作,速度快,效率高;Guava 相比 Redis 来说,应用和cache是在同一个进程内部,请求缓存非常迅速,没有过多的网络开销。redis 的好处是自身就是一个独立的应用,多个应用可以共享缓存。我们应该根据数据类型、业务场景来判断应该使用哪种类型的缓存,以达到减少计算量,提高响应速度的目的。
本地缓存适用场景(需都满足)
-
愿意消耗一些内存空间来提升速度
-
预料到某些键会被多次查询
-
缓存中存放的数据总量不会超出内存容量
-
要更快的响应,缓存不需要网络 io(集中式缓存需要额外网络 io)
如何使用 Guava 缓存
Guava Cache 是 Google 开源的 Java 重用工具集库 Guava 里的一款缓存工具,下面介绍接入 guava 缓存的步骤及使用过程中踩过的坑
Guava Cache 接入demo
- 1、导入 Maven 引用
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
- 2、Cache 初始化,使用了 Builder 设计模式,可自行设置各类参数
private final LoadingCache<Long, TestDemo> demo = CacheBuilder.newBuilder()
//设置 cache 的初始大小为10,要合理设置该值
.initialCapacity(10)
//设置并发数为5,即同一时间最多只能有5个线程往 cache 执行写入操作
.concurrencyLevel(5)
//最大 key 个数
.maximumSize(100)
//移除监听器
.removalListener(removalListener)
//设置 cache 中的数据在写入之后的存活时间为10秒
.expireAfterWrite(10, TimeUnit.SECONDS)
//构建 cache 实例
.build(new CacheLoader<Long, TestDemo>() {
@Override
public TestDemo load(Long id) throws Exception {
// 读取 db 数据
}
});
RemovalListener<String, String> removalListener = new RemovalListener<String, String>() {
public void onRemoval(RemovalNotification<id, TestDemo> removal) {
System.out.println("[" + removal.getKey() + ":" + removal.getValue() + removal.getCause() + "] is evicted!");
}
};
- 3、 如果缓存加载方法时出现了异常,那么下一次是缓存异常还是正常数据?
public class TestDemoImpl implements TestDemo {
int time;
private final LoadingCache<Long, TestDemo> demo;
this.demo1 = CacheBuilder.newBuilder()
.expireAfterWrite(duration, TimeUnit.HOURS)
.build(new CacheLoader<Long, TestDemo>() {
@Override
public TestDemo load(Long id) throws Exception {
// 查询 db
if (time++==0) {
throw new RunTimeException();
}
return result;
}
});
}
public static void main(String[] args) {
try {
try {
TestDemo testDemo = demoCache.getUnchecked(21L);
System.out.println("第一次查询:" + testDemo);
} catch (Exception e) {
}
TestDemo testDemo1