公众号后台回复“面试”,获取精品学习资料
扫描下方海报了解专栏详情
本文来源:阿飞的博客
《Java工程师面试突击(第3季)》重磅升级,由原来的70讲增至160讲,内容扩充一倍多,升级部分内容请参见文末
压力测试
简介
自动把数据加载到本地缓存中,并且可以配置异步; 基于数量剔除策略; 基于失效时间剔除策略,这个时间是从最后一次访问或者写入算起; 异步刷新; Key会被包装成Weak引用; Value会被包装成Weak或者Soft引用,从而能被GC掉,而不至于内存泄漏; 数据剔除提醒; 写入广播机制; 缓存访问可以统计;
使用
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.8.4</version>
</dependency>
然后构造Cache使用即可:
Cache<String, String> cache = Caffeine.newBuilder()
数量上限
.maximumSize(1024)
/ 过期机制
.expireAfterWrite(5, TimeUnit.MINUTES)
// 弱引用key
.weakKeys()
// 弱引用value
.weakValues()
// 剔除监听
.removalListener((RemovalListener<String, String>) (key, value, cause) ->
System.out.println("key:" + key + ", value:" + value + ", 删除原因:" + cause.toString()))
.build();
// 将数据放入本地缓存中
cache.put("username", "afei");
cache.put("password", "123456");
// 从本地缓存中取出数据
System.out.println(cache.getIfPresent("username"));
System.out.println(cache.getIfPresent("password"));
System.out.println(cache.get("blog", key -> {
// 本地缓存没有的话,从数据库或者Redis中获取
return getValue(key);
}));
AsyncLoadingCache<String, String> cache = Caffeine.newBuilder()
// 数量上限
.maximumSize(2)
// 失效时间
.expireAfterWrite(5, TimeUnit.MINUTES)
.refreshAfterWrite(1, TimeUnit.MINUTES)
// 异步加载机制
.buildAsync(new CacheLoader<String, String>() {
@Nullable
@Override
public String load(@NonNull String key) throws Exception {
return getValue(key);
}
});
System.out.println(cache.get("username").get());
System.out.println(cache.get("password").get(10, TimeUnit.MINUTES));
System.out.println(cache.get("username").get(10, TimeUnit.MINUTES));
System.out.println(cache.get("blog").get());
过期机制
expireAfterWrite:表示自从最后一次写入后多久就会过期; expireAfterAccess:表示自从最后一次访问(写入或者读取)后多久就会过期; expireAfter:自定义过期策略;
刷新机制
.build(new CacheLoader<String, String>() {
@Override
public String load(String k) {
// 这里我们就可以从数据库或者其他地方查询最新的数据
return getValue(k);
}
});
剔除机制
「EXPLICIT」:调用方法(例如:cache.invalidate(key)、cache.invalidateAll)显示剔除数据; 「REPLACED」:不是真正被剔除,而是用户调用一些方法(例如:put(),putAll()等)盖了之前的值; 「COLLECTED」:表示缓存中的Key或者Value被垃圾回收掉了; 「EXPIRED」: expireAfterWrite/expireAfterAccess约定时间内没有任何访问导致被剔除; 「SIZE」:超过maximumSize限制的元素个数被剔除的原因;
GuavaCache和Caffeine差异
剔除算法方面,GuavaCache采用的是「LRU」算法,而Caffeine采用的是「Window TinyLFU」算法,这是两者之间最大,也是根本的区别。 立即失效方面,Guava会把立即失效 (例如:expireAfterAccess(0) and expireAfterWrite(0)) 转成设置最大Size为0。这就会导致剔除提醒的原因是SIZE而不是EXPIRED。Caffiene能正确识别这种剔除原因。 取代提醒方面,Guava只要数据被替换,不管什么原因,都会触发剔除监听器。而Caffiene在取代值和先前值的引用完全一样时不会触发监听器。 异步化方方面,Caffiene的很多工作都是交给线程池去做的(默认:ForkJoinPool.commonPool()),例如:剔除监听器,刷新机制,维护工作等。
内存占用对比
LRU P.K. W-TinyLFU




Guava迁移
// Guava's LoadingCache interfaceLoadingCache<Key, Graph> graphs = CaffeinatedGuava.build( Caffeine.newBuilder().maximumSize(10_000), new CacheLoader<Key, Graph>() { // Guava's CacheLoader @Override public Graph load(Key key) throws Exception { return createExpensiveGraph(key); } });
参考
END
《Java工程师面试突击第三季》加餐部分大纲:(注:1-66讲的大纲请扫描文末二维码,在课程详情页获取)
详细的课程内容,大家可以扫描下方二维码了解: