【问题标题】:Guava thread management when pre-loading and refreshing cache entries预加载和刷新缓存条目时的 Guava 线程管理
【发布时间】:2018-10-01 09:03:07
【问题描述】:

我们希望使用 guava 缓存来缓存第三方数据以获得更好的响应时间。需要通过一系列 api 调用来预加载缓存(大约 4000 次 api 调用)。 api 响应包含缓存键及其值。这些 api 调用需要从多个线程(即线程池)并行进行,以加快缓存加载。 每个缓存条目都有一个过期时间。这可以使用 expireAfterAccess() 调用来设置。 缓存条目过期后,需要在后台自动刷新。还应该有一种方法(api),通过它我们可以停止这种后台缓存刷新,这样我们就不会无休止地进行 api 调用。一旦在配置的时间间隔后停止接收用户请求,我们将调用此 api。

是否可以将缓存加载和刷新的线程管理委托给番石榴?即给定api调用,将json响应映射到java对象和缓存键值设计的代码,guava可以自己执行预加载和刷新吗?

谢谢。

【问题讨论】:

  • AFIAK Guava 没有刷新功能。具有此功能的轻量级进程缓存替代品将是 Caffeine 或 cache2k。这是最近关于该主题的讨论:github.com/ben-manes/caffeine/issues/261。请修改您的问题,以防您接受 Guava 的替代建议。
  • @cruftex - 感谢您的评论。您是否在最新版本 (v26) 和即将发布的路线图中验证了这一点?没有办法执行自动刷新?
  • 有趣。我仔细检查了一下,实际上我错了。番石榴具有自动刷新功能。

标签: java caching guava


【解决方案1】:

可以通过CacheBuilder.refreshAfterWrite() 启用 Guava 中的自动刷新。相关语义描述为:

指定活动条目有资格自动刷新一次 条目创建后经过了固定的持续时间,或最长 最近更换了它的价值。 [ ... ] 当前自动刷新 在第一个陈旧的条目请求发生时执行。

当覆盖 CacheLoader.reload() 方法时,您可以使用线程池异步加载值。

这种行为的问题是,在新值加载之前,如果成功,您总是会读取一些陈旧值。另一种缓存实现,如cache2k 在持续时间后立即开始刷新。后一种方法会导致更新的数据,但可能会导致更多不必要的读取。在此处查看最近的一些讨论:https://github.com/ben-manes/caffeine/issues/261

【讨论】:

  • 读取旧值直到新值被加载是我们的用例可以接受的。 refreshAfterWrite() 方法确实有助于自动刷新,但我不确定默认实现是否在后台执行。在我写here 的测试中,似乎主线程正在刷新。这是output。请注意最后一个断言,它指示第二个条目的自动刷新是在主线程中的睡眠调用完成后触发的。想法?
  • 代码在哪里?尽管我不是具有相似语义的 Google Guava 或 Caffeine 专家,但我认为第一次过时的读取会触发加载程序。
  • 既然回答了一般问题,那么在您的实际代码中添加一个后续问题可能是个好主意。通常谷歌的人也会帮忙。
  • 这是代码 - pastebin.com/SV6ns38M,这是输出 - pastebin.com/Z5gCiWLm
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-06
  • 2014-05-01
  • 1970-01-01
  • 2014-02-23
  • 1970-01-01
相关资源
最近更新 更多