我有一个
LoadingCache
,可以从一些数据加载 Netty ByteBuf
。一旦条目被逐出,我需要能够使用 release()
释放此数据,但是存在一种竞争条件,即在我能够 retain()
之前条目已被逐出,并且返回的 ByteBuf
无效。
这是我正在尝试做的一个示例 - 当在 get 和保留之间调用删除侦听器时,会发生竞争。
LoadingCache<String, ByteBuf> cache = Caffeine.newBuilder()
.maximumSize(128)
.evictionListener(
(RemovalListener<String, ByteBuf>) (string, buf, removalCause) -> {
buf.release();
}
)
.build(
key -> {
ByteBuf byteBuf = null;
// TODO: Create the ByteBuf from a pool
return byteBuf;
}
);
ByteBuf buffer = cache.get("hello").retain();
// If the entry is evicted between call to get and the retain then a race condition occurs
// That means the reference count drops to 0 before the retain is invoked
有没有办法让 Caffeine 在从 get 返回之前安全地、原子地调用保留?
您可以使用
asMap().compute
对条目执行读/写操作。
Cache<String, ByteBuf> cache = Caffeine.newBuilder()
.evictionListener((String string, ByteBuf buf, RemovalCause cause) -> buf.release())
.maximumSize(128)
.build();
ByteBuf buffer = cache.asMap().compute(key, (k, buf) -> {
if (buf == null) {
buf = // TODO: Create the ByteBuf from a pool
}
buf.retain();
return buf;
});
您可能还对 固定 感兴趣,您可以通过指定该条目消耗零容量来将其标记为不可逐出,因此它将被大小逐出跳过。
Cache<String, ByteBuf> cache = Caffeine.newBuilder()
.weigher((String string, ByteBuf buf) -> (buf.refCnt() == 0) ? 1 : 0)
.maximumWeight(128)
.build();
public ByteBuf acquire(String key) {
// above
}
public void release(String key) {
cache.asMap().compute(key, (k, buf) -> {
buf.release();
return buf;
});
}