一、Caffeine介绍
Caffeine是一个基于Java 8的高性能本地缓存框架,采用了W-TinyLFU(LUR和LFU的优点结合)算法,实现了缓存高命中率、内存低消耗。缓存性能接近理论最优,属于是Guava Cache的增强版。在并发读、并发写、并发读写三个场景下Caffeine的性能最优。
二、使用方式
1、在pom.xml 中添加 caffeine 依赖
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
2、参数说明
参数 |
说明 |
expireAfterWrite |
写缓存后n秒钟过期 |
expireAfterAccess |
读写缓存后n秒钟过期 |
refreshAfterWrite |
写入后多久刷新,刷新是基于访问(支持异步和同步刷新)。 只阻塞当前数据加载的线程,其他线程返回旧值,刷新完成才会返回新的取值。 |
expireAfter |
自定义淘汰策略, Caffeine 通过时间轮算法来实现不同key 的不同过期时间 |
maximumSize |
缓存key最大个数 |
weakKeys |
key设置为弱引用,在 GC 时可以直接淘汰 |
weakValues |
value设置为弱引用,在 GC 时可以直接淘汰 |
softValues |
value设置为软引用,在内存溢出前可以直接淘汰 |
executor |
选择自定义线程池,默认线程池是 ForkJoinPool.commonPool() |
maximumWeight |
设置缓存最大权重 |
weigher |
设置具体key权重 |
recordStats |
缓存的统计数据,比如命中率等 |
removalListener |
缓存淘汰监听器 |
writer |
缓存写入、更新、淘汰的监听器 |
3、创建对象
private LoadingCache<String, List<Integer>> cache = Caffeine.newBuilder()
//cache最大缓存数
.maximumSize(500)
//设置写缓存后n秒钟过期
.expireAfterWrite(17, TimeUnit.SECONDS)
.build();
4、缓存类型
4.1 手动加载cache:提供搜索查找、更新和移除缓存元素。缓存数据不存在,需要手动加载。
Cache<String, List<Integer>> cache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(500)
.build(new CacheLoader<String, List<Integer>>() {
@Override
public List<Integer> load(String key){
return createCache(key);
}
});
private static final String KEY = "key";
private void getCache() {
//1.查询缓存,没有返回null
List<Integer> list = cache.getIfPresent(KEY);
//2.查找缓存,不存在生成缓存,生成失败返回null
list = cache.get(KEY, k -> createCache(KEY));
//3.添加或者更新一个缓存元素
cache.put(KEY, list);
//4.移除一个缓存元素
cache.invalidate(KEY);
}
4.2 自动加载Loading Cache:LoadingCache比Cache多了如果缓存不存在,会通过CacheLoader.load生成对应的缓存数据到缓存中,实现自动加载。
LoadingCache<String, List<Integer>> loadingCache = Caffeine.newBuilder()
.maximumSize(500)
.build(key -> createCache(key));
private void getLoadingCache() {
//1.查找缓存,不存在生成缓存,生成失败返回null
List<Integer> list = loadingCache.get(KEY);
//2.批量查找缓存,如果缓存不存在则生成缓存
List<String> requestKeys = new ArrayList<>();
Map<String, List<Integer>> map = loadingCache.getAll(requestKeys);
}
4.3 手动异步加载Async Cache:AsyncCache是Cache异步形式,提供了Executor生成缓存并返回CompletableFuture的能力。默认的线程池实现是 ForkJoinPool.commonPool() 。也可以使用Caffeine.executo设置自定义的线程池。
AsyncCache<String, List<Integer>> asyncCache = Caffeine.newBuilder()
.maximumSize(500)
.buildAsync();
private void getAsyncCache() {
//1.查询缓存,没有返回null
CompletableFuture<List<Integer>> graph = asyncCache.getIfPresent(KEY);
//2.查找缓存,如果不存在,异步生成
graph = asyncCache.get(KEY, k -> createCache(KEY));
//3.添加或者更新一个缓存元素
asyncCache.put(KEY, graph);
//4.移除一个缓存元素
asyncCache.synchronous().invalidate(KEY);
}
4.4 自动异步加载Async Loading Cache:AsyncLoadingCache是LoadingCache的异步形式,返回一个包含取值的CompletableFuture。
AsyncLoadingCache<String, List<Integer>> asyncLoadingCache = Caffeine.newBuilder()
.maximumSize(500)
.buildAsync(key->{
log.info("缓存不存在异步加载");
return createCache(key);
});
//查找不存在异步生成
CompletableFuture<Graph> graph = cache.get(key);
//批量查找不存在异步生成
CompletableFuture<Map<Key, Graph>> graphs = cache.getAll(keys);
5、驱逐策略
Caffeine提供三类驱逐策略:基于大小、基于时间、基于引用。
5.1 基于大小
//1:个数(大小)
LoadingCache<String, List<Integer>> loadingCache = Caffeine.newBuilder()
.maximumSize(500)
.build();
//2.基于缓存内元素权重
LoadingCache<String, List<Integer>> loadingCache = Caffeine.newBuilder()
.maximumWeight(200)
.weigher((String key, List<Integer> list) -> list.size())
.build();
备注:maximumWeight 与 maximumSize 不可以同时使用。
5.2 基于时间
//1.设置写缓存后n秒钟过期
LoadingCache<String, List<Integer>> loadingCache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS)
.build();
//2.设置读写缓存后n秒钟过期,类似于Guava Cache的expireAfterWrite
LoadingCache<String, List<Integer>> loadingCache = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build();
//3.自定义策略需要自己实现Expiry接口。
LoadingCache<String, List<Integer>> loadingCache = Caffeine.newBuilder()
.expireAfter(new Expiry<String, St