guava缓存的使用
1.基础-Cache直接存取
普通的key-value缓存类似Map的使用:
public static void main(String[] args) throws Exception {
//创建一个1000长度的缓存,10毫秒失效
Cache<String, Stu> cache = CacheBuilder
.newBuilder().maximumSize(1000).expireAfterWrite(10, TimeUnit.MILLISECONDS)
.build();
//放入一个数据,key为1
cache.put("1", new Stu("name1"));
//放入后直接取,有值
System.out.println("放入之后getIfPresent:" + cache.getIfPresent("1"));
Thread.sleep(11);
//休息11秒再取,已经失效,无值
System.out.println("休息11毫秒,失效后getIfPresent:" + cache.getIfPresent("1"));
}
private static record Stu(String name) {
}
输出如下,符合预期
放入之后getIfPresent:Stu[name=name1]
休息11毫秒,失效后getIfPresent:null
2.基础-Cache并发重复加载
guava中不存在,触发回源(可能是Redis或库),并发场景中,同一个数据会多次回源:
//创建一个1000长度的缓存,1秒失效
private static Cache<Long, Stu> skuCache = CacheBuilder.newBuilder().maximumSize(1000)
.expireAfterWrite(1000, TimeUnit.MILLISECONDS).build();
private static Stu getStu(Long id) throws Exception {
Stu stu = skuCache.getIfPresent(id);
if (null != stu) {
return stu;
}
//模拟回源加载数据需要时间,回源加载数据并放入缓存
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
stu = new Stu(id, "name" + id);
skuCache.put(id, stu);
System.out.println("回源加载:" + id);
return stu;
}
public static void main(String[] args) throws Exception {
//三个线程并发请求同一个数据,会加载3次
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
System.out.println(getStu(1L));
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
private static record Stu(Long id, String name) {
}
执行输出如下,同样的数据name1在三个线程中被重复加载3次。
回源加载:1
回源加载:1
回源加载:1
Stu{name='name1'}
Stu{name='name1'}
Stu{name='name1'}
3.基础-通过LoadingCache来避免并发重复加载
代码如下:
//创建一个1000长度的缓存,1秒失效
private static LoadingCache<Long, Stu> cacheLoad = CacheBuilder.newBuilder().maximumSize(1000).expireAfterWrite(30, TimeUnit.MILLISECONDS)
.build(new CacheLoader<Long, Stu>() {
@Override
public Stu load(Long id) throws Exception {
//模拟回源加载数据需要时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("回源加载:" + id);
return new Stu(id, "name" + id);
}
});
public static void main(String[] args) throws Exception {
//三个线程并发请求同一个数据,只会加载1次
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
System.out.println(cacheLoad.get(1L));
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
执行结果如下,只回源了一次:
回源加载:1
Stu[id=1, name=name1]
Stu[id=1, name=name1]
Stu[id=1, name=name1]