如何在RxJava中缓存项目并避免缓存标记?

时间:2018-05-07 08:57:38

标签: java-8 rx-java2 caffeine

假设我有以下代码:

Entity getEntity(GUID entityId) {
  Entity entity = entityLRUCache.get(entityId);
  if (entity == null) {
    entity = longLoadFromDatabase(entityId);
    entityLRUCache.put(entityId, entity);
  }
  return entity;
}

Thanks to @BenManes我可以使用Caffeine框架解决缓存踩踏问题:

Entity getEntity(GUID entityId) {
  return entityCache.get(entityId, this::longLoadFromDatabase);
}

但是现在方法longLoadFromDatabase返回Single<Entity>而不是实体本身(get的第二个参数是来自int -> Entity的映射器),所以之前的解决方案不会再努力了。

2 个答案:

答案 0 :(得分:2)

您可以在并发地图中使用SingleSubject作为占位符:

ConcurrentMap<GUID, SingleSubject<Entity>> map = ...

public Single<Entity> getEntity(GUID guid) {
    SingleSubject<Entity> e = map.get(guid);
    if (e == null) {
        e = SingleSubject.create();
        SingleSubject<Entity> f = map.putIfAbsent(guid, e);
        if (f == null) {
            longLoadFromDatabase(guid).subscribe(e);
        } else {
            e = f;
        }
    }
    return e;
}

答案 1 :(得分:1)

将@akarnokd建议与Caffeine的异步支持相结合,您可以将AsyncLoadingCache与Rx的转换器结合使用。

AsyncLoadingCache<Integer, Entity> cache = Caffeine.newBuilder()
    .buildAsync((key, executor) -> SingleInterop.get()
        .apply(longLoadFromDatabase(key)).toCompletableFuture());
...
return SingleInterop.fromFuture(cache.get(123));

如果将来因异常而失败或解析为空值,缓存将自动删除该条目。