在番石榴图书馆,我很困惑为什么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()
到底做了什么?
答案 0 :(得分:13)
Guava的缓存是围绕锁定摊销设计的,cleanUp
方法强制缓存达到一致状态。 Map.size()
方法是近似值,但可能会计算由于到期或参考驱逐而等待删除的条目。 Guava高速缓存中近似值的可见性对于应用程序来说很少有用,它往往将高速缓存视为瞬态数据存储。来自Map的缓存的不同期望导致asMap
方法允许将缓存视为地图,但不喜欢开发人员以这种方式感知它。
StrangleLoop 2011大会slides介绍了缓存的实施细节。 Guava缓存源自ConcurrentLinkedHashMap
的{{3}}也可能引起关注,但描述的方法略有不同。
答案 1 :(得分:11)
asMap()
个视图可以遍历缓存中的每个元素,因此可以跳过待处理清除的无效条目。另一方面,size()
预计会是一个快速操作,只是为了获得更准确的大小估计而遍历整个缓存是愚蠢的。
CacheBuilder
javadocs详细介绍了在各种情况下需要进行的清理工作(例如expireAfterWrite
)。