【问题标题】:Why is Cache.asMap() not consistent with Cache.size()?为什么 Cache.asMap() 与 Cache.size() 不一致?
【发布时间】:2012-05-04 04:45:54
【问题描述】:

在Guava库中,我很困惑为什么Cache.asMap()Cache.size()不一致,除非调用Cache.cleanUp()

Cache<Object, Object> cache = CacheBuilder.newBuilder()
           .expireAfterWrite(1, TimeUnit.SECONDS)
           .build();
cache.get(...);
...
//After some seconds, all entries are expired.
//cache.asMap() is EMPTY Map, but cache.size() != 0

所以我的问题是:Cache.asMap()Cache.size() 不一致是错误吗? 虽然我注意到Cache.size() 的javadoc 是:

  /**
   * Returns the **approximate** number of entries in this cache.
   */

我只能猜测它与并发环境有关。 Cache.cleanUp() 究竟做了什么?

【问题讨论】:

    标签: java caching concurrency guava


    【解决方案1】:

    Guava 的缓存是围绕锁摊销设计的,cleanUp 方法强制缓存达到一致状态。 Map.size() 方法是一个近似值,但可能会计算由于过期或引用驱逐而等待删除的条目。 Guava 缓存中近似值的可见性很少引起应用程序的兴趣,应用程序倾向于将缓存视为临时数据存储。缓存与 Map 的不同期望导致 asMap 方法允许将缓存视为地图,但不喜欢开发人员以这种方式感知它。

    缓存的实现细节在 StrangleLoop 2011 会议slides 中有介绍。 ConcurrentLinkedHashMapdesign document 是 Guava 缓存的来源,它可能也很有趣,但描述的方法略有不同。

    【讨论】:

      【解决方案2】:

      Ben 给出了很好的高层回应。低级响应是:

      asMap() 视图可以遍历缓存中的每个元素,因此可以跳过等待清理的无效条目。另一方面,size() 预计会是一个快速操作,而为了获得更准确的大小估计而遍历整个缓存是愚蠢的。

      CacheBuilder javadocs 更详细地介绍了在各种情况下需要进行的清理(例如 expireAfterWrite,在您的情况下)。

      【讨论】:

      • 谢谢你,查尔斯!我粗略地浏览了源代码,'size()' 只是总结了 Segment 的数量,正如你所提到的 - “为了获得更准确的大小估计而遍历整个缓存是愚蠢的”:) 高度复杂的设计!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-18
      相关资源
      最近更新 更多