移除、统计与半持久化
原创大约 3 分钟
移除
这里的移除
有两层意思。
手动移除,而不是等到它自己失效,这是所有缓存都需要支持的功能。
和Guava Cache一样,Caffeine也有移除监听器,可以完成相关的回调操作。
手动移除
package com.xiangwang.commons.caffeine;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import java.util.concurrent.TimeUnit;
/**
* 手动移除
*
*/
public class CaffeineTest11 {
public static void main(String[] args) throws InterruptedException {
LoadingCache<String, Object> caffeine = Caffeine.newBuilder()
.initialCapacity(1)
.maximumSize(100)
.build(key -> "default");
caffeine.put("k1", "v1");
caffeine.put("k2", "v2");
caffeine.put("k3", "v3");
System.out.println(caffeine.get("k1"));
// 删除k1
caffeine.invalidate("k1");
System.out.println(caffeine.get("k1"));
System.out.println(caffeine.get("k2"));
System.out.println(caffeine.get("k3"));
// 删除全部
caffeine.invalidateAll();
System.out.println(caffeine.get("k2"));
System.out.println(caffeine.get("k3"));
}
}
运行后输出如下。
v1
default
v2
v3
default
default
移除监听
package com.xiangwang.commons.caffeine;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.RemovalListener;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.concurrent.TimeUnit;
/**
* 移除监听
*
*/
public class CaffeineTest12 {
/**
* 创建一个监听器
*
*/
private static class CacheRemovalListener implements RemovalListener<String, String> {
@Override
public void onRemoval(@Nullable String key, @Nullable String value, @NonNull RemovalCause removalCause) {
System.out.println(key + " 被删除了, value = " + value);
}
}
public static void main(String[] args) throws InterruptedException {
LoadingCache<String, String> caffeine = Caffeine.newBuilder()
.removalListener(new CacheRemovalListener())
.initialCapacity(1)
.maximumSize(100)
.build(key -> "default");
caffeine.put("username", "lixingyun");
TimeUnit.SECONDS.sleep(1);
System.out.println(caffeine.get("username"));
// 执行删除动作
caffeine.invalidate("username");
TimeUnit.SECONDS.sleep(1);
System.out.println(caffeine.get("username"));
}
}
运行后输出如下。
lixingyun
username 被删除了, value = lixingyun
default
统计
Caffeine也提供了一个仪表盘用来观察缓存状态。
hitRate()
:返回命中与请求的比率。hitCount()
: 返回命中缓存的总数。evictionCount()
:缓存逐出的数量。averageLoadPenalty()
:加载新值所花费的平均时间。
package com.xiangwang.commons.caffeine;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import java.util.concurrent.TimeUnit;
/**
* 统计
*
*/
public class CaffeineTest13 {
public static void main(String[] args) throws InterruptedException {
LoadingCache<String, String> caffeine = Caffeine.newBuilder()
.initialCapacity(1)
.maximumSize(100)
// 开启它统计才能起作用
.recordStats()
.build(key -> "default");
caffeine.put("username", "lixingyun");
TimeUnit.SECONDS.sleep(1);
System.out.println(caffeine.get("username"));
// 执行删除动作
caffeine.invalidate("username");
TimeUnit.SECONDS.sleep(1);
System.out.println(caffeine.get("username"));
// 开启统计
// 0.5,因为命中1次,未命中1次
System.out.println(caffeine.stats().hitRate());
// 1,命中次数
System.out.println(caffeine.stats().hitCount());
// 缓存逐出量
System.out.println(caffeine.stats().evictionCount());
// 加载数据花费的平均时间
System.out.println(caffeine.stats().averageLoadPenalty());
// 加载失败次数
System.out.println(caffeine.stats().loadFailureCount());
// 总的加载时间
System.out.println(caffeine.stats().totalLoadTime());
}
}
运行后输出如下。
lixingyun
default
0.5
1
0
11494.0
0
11494
半持久化
Caffeine把操作缓存和操作外部资源这两种操作,封装成一个同步的原子性操作。
CacheWriter
不能与弱引用weakKeys
或异步填充AsyncLoadingCache
结合使用。
package com.xiangwang.commons.caffeine;
import com.github.benmanes.caffeine.cache.CacheWriter;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.RemovalCause;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.concurrent.TimeUnit;
/**
* 半持久化
*
*/
public class CaffeineTest14 {
public static void main(String[] args) throws InterruptedException {
LoadingCache<String, String> caffeine = Caffeine.newBuilder()
.initialCapacity(1)
.maximumSize(100)
.writer(new CacheWriter<String, String>() {
@Override
public void write(@NonNull String key, @NonNull String value) {
// 可以在这里将缓存数据写入文件、缓存、数据库、HDFS等不同存储介质中,形成二级缓存
System.out.println("数据已保存到Redis......");
}
@Override
public void delete(@NonNull String key, @Nullable String value, @NonNull RemovalCause removalCause) {
// 这里可以实现受害者缓存(Victim Cache)模式:将被删除的数据写入二级缓存,或从资源中清除
System.out.println("数据已保存到HDFS......");
}
})
.build(key -> "default");
caffeine.put("username", "lixingyun");
TimeUnit.SECONDS.sleep(1);
System.out.println(caffeine.get("username"));
// 执行删除动作
caffeine.invalidateAll();
}
}
运行后输出如下。
数据已保存到Redis......
lixingyun
数据已保存到HDFS......
所谓受害者缓存(Victim Cache)模式的作用如下。
当一个数据块被逐出缓存时,并不直接丢弃,而是暂先进入
受害者缓存队列
。如果
受害者缓存队列
已满,就替换掉其中一项。如果在
受害者缓存队列
中发现匹配数据,就将此数据与缓存中的不匹配数据块做交换,同时返回给处理器。
感谢支持
更多内容,请移步《超级个体》。