Guava缓存:取消特定缓存值的驱逐

4

嘿,

目前正在使用guava对用户进行缓存。所以我的问题是:是否可以使用guava来限制一个条目的逐出,如果缓存的对象具有特定的属性值。例如,如果user.isOnline()返回true,则即使他在特定时间(.expireAfterAccess(KEEP_LOADED, TimeUnit.SECONDS))内没有被访问,也不会将其逐出。

编辑:

我在CacheBuilder.weighter(...)的javadoc中发现了这个:

当一个条目的权重为零时,它将不会被考虑作为基于大小的驱逐(尽管它仍然可能被其他方式逐出)。

但如果用户在线,我不想以任何方式驱逐他。

基本上,我使用这种方式缓存我的用户:

        this.cache = CacheBuilder.newBuilder()
            .maximumSize(MAX_CACHED_USERS)
            .expireAfterAccess(KEEP_LOADED, TimeUnit.SECONDS)
            .build(new UserLoader(core));

编辑:

好的,我可以使用 weighter 来限制缓存的大小。对于在线用户,我可以返回 0,对于其他用户则返回 1。这将导致缓存保留在线用户。但如果能够使用 maximumSize 和 expireAfterAccess 就更好了。但是 CacheBuilder.weighter(...) 不会阻止 expireAfterAccess(...) 设置以驱逐旧用户。

编辑:

也许有一些方法可以取消驱逐,但我不确定如何操作 :/

相关文章:从 Guava RemovalListener 重新插入条目是否安全?

Max


@Ray soo 当缓存对象被驱逐时,reload()会被调用吗? - maxammann
由于javadocs中没有信息:计算或检索与已缓存键对应的替换值。当通过CacheBuilder.refreshAfterWrite刷新现有缓存条目或通过调用LoadingCache.refresh刷新时,将调用此方法。 - maxammann
4
不,没有像你试图做的那样完成此操作的方法。听起来你应该在用户离线时显式地执行“invalidate”操作。 - Louis Wasserman
@LouisWasserman 可能是可以的,但我的目标是在断开连接后让用户保持特定的时间,例如如果用户刚刚重新连接。 - maxammann
我想我会设置一个缓存的最大权重并删除基于时间的驱逐。谢谢,如果你想的话可以把你的评论发表为答案,我会给你一个赞。 - maxammann
显示剩余2条评论
1个回答

1

你链接的问题直接描述了如何处理此模式。

我会使用一个映射和一个缓存。使用映射来处理仍在进行中的作业,并使用缓存的RemovalListener从地图中删除条目?

简而言之,如果有不想被清除的数据,则不应该将其放入可清除的数据结构中。

对于您的用例,您需要维护已登录用户的映射和最近登录用户的缓存。当用户登录时,它们存储在标准映射中。当他们注销时,其对象移到缓存中,随后被逐出。

您可以(并且应该)将此行为隐藏在包含映射和缓存的对象内部。可能看起来像这样:

public class UserStore {
  private final ConcurrentHashMap<Key, User> loggedIn;
  private final LoadingCache<Key, User> recentlyAccessed;

  ...

  public User getUser(Key userKey) {
    User user = loggedIn.get(userKey);
    if (user != null) {
      return user;
    }
    return recentlyAccessed.getUnchecked(userKey); // or .get() if necessary
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接