添加mavne依赖
com.google.guava
guava
29.0-jre
测试代码及注释
package com.swkj.customer.restapi.test;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* @Description:
* @Author: GE LIANG
* @Date: 2022/8/26 9:33
*/
public class CacheTest {
private static LoadingCache loadingCache = CacheBuilder.newBuilder()
// 并发级别
.concurrencyLevel(8)
// 初始容量
.initialCapacity(10)
// 超出阈值之后使用LRU算法溢出缓存项,只会在写入操作时候同步移除
.maximumSize(100)
// 缓存项自动定时刷新-》缓存项只有在被检索时才会真正刷新,即只有刷新间隔时间到了你再去get(key)才会重新去执行Loading否则就算刷新间隔时间到了也不会执行loading操作
.refreshAfterWrite(3, TimeUnit.MINUTES)
.build(new CacheLoader() {
@Override
public String load(String key) throws Exception {
/**
* 不同缓存数据要使用不同loadingCache获取
*/
/**
* 方式1-单个插入缓存
*/
// 回源操作(当通过get(key)的方式不存在的时候出发)
String result = "需要缓存的单条数据(可以是任何类型)";
return result;
/**
* 方式2-批量插入缓存
*/
// Map batchCacheMap = new HashMap<>();
// batchCacheMap.put("key1", "abc123");
// batchCacheMap.put("key2", "模拟数据-需要获取的时候使用loadingCache.get(\"key2\")即可");
// loadingCache.putAll(batchCacheMap);
// return batchCacheMap.get(key);
}
});
public static void main(String[] args) throws ExecutionException {
/**
* 方式一的获取方式
*/
loadingCache.get("resultKey");
/**
* 方式二的获取方式
*/
// loadingCache.get("key1");
// loadingCache.get("key2");
}
}
GuavaCache为开发人员提供了三种缓存被动更新机制,如下所示:
expireAfterWrite机制:当缓存项过期触发回源操作时,GuavaCache会通过重入锁ReentrantLock严格地控制单机只能有一个线程在执行操作,而其他线程则必须阻塞等待直至回源操作完成,不过当回源操作结束后,之前那些被阻塞的线程仍然会逐一获取锁来验证回源结果;也就是说,每个线程必须轮流地经历取锁、取值,以及释放锁的过程,这样会存在一定程度上的性能损耗,适用缓存数据强一致性的场景。
refreshAfterWrite机制:可以有效避免expireAfterWrite 机制在并发环境下因为锁资源竞争所带来的性能损耗,同expireAfterWrite类似,在执行回源操作时,单机仍然只允许一个线程在执行操作,但其他线程并不会阻塞,而是直接返回旧值;这么做虽然可以提升性能,但却仍然存在一个明显的问题,那就是refreshAfterWrite机制并不能够严格地确保返回值都是新值,适用缓存数据可以容忍短暂时间不一致场景。
当然具体应该使用哪一种缓存被动更新机制,则还需要结合具体的业务场景而定。