为什么Cache.asMap()与Cache.size()不一致?

时间:2012-05-04 04:45:54

标签: java caching concurrency 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()到底做了什么?

2 个答案:

答案 0 :(得分:13)

Guava的缓存是围绕锁定摊销设计的,cleanUp方法强制缓存达到一致状态。 Map.size()方法是近似值,但可能会计算由于到期或参考驱逐而等待删除的条目。 Guava高速缓存中近似值的可见性对于应用程序来说很少有用,它往往将高速缓存视为瞬态数据存储。来自Map的缓存的不同期望导致asMap方法允许将缓存视为地图,但不喜欢开发人员以这种方式感知它。

StrangleLoop 2011大会slides介绍了缓存的实施细节。 Guava缓存源自ConcurrentLinkedHashMap的{​​{3}}也可能引起关注,但描述的方法略有不同。

答案 1 :(得分:11)

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

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

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