4

当前的地图驱逐算法非常懒惰。看起来过期的对象只有在访问数据结构时才会被驱逐。

例如,从地址到索引器的映射定义为:

ConcurrentMap<Address, Indexer> indexers = new MapMaker()
  .expireAfterAccess( EXPIRATION, TimeUnit.SECONDS)
  .evictionListener( new IndexEvicted())
  .makeMap();

导致非常令人惊讶的模式:虽然containsKey()对于给定的地址返回 false,但在该地址的索引器被驱逐后立即返回。

使清理过程更加实时的推荐方法是什么?即删除接近实际到期时间的对象。

更新:我想更清楚地说明我所说的实时是什么意思。对于上面的示例, EXPIRATION 为 10 秒,我希望看到插入的对象在最后一次访问后 10 秒内被驱逐。现在不会发生这种情况 - 必须以某种方式使用地图来开始驱逐。如果地图完全未使用,则该对象可以在那里停留数年。

4

3 回答 3

4

为了及时驱逐,Guava 需要实现某种后台线程或定时重复任务。这样做会使映射更重,更难在 J2EE 等环境或安全策略阻止线程随意生成的环境中使用。

如果您关心及时驱逐,请设置您自己的接触地图的定时线程。

另一方面,我同意让垃圾收集器触发驱逐会很好......例如通过使用 SoftReference 和终结器。(是的,我知道终结者大多是邪恶的,我只是建议一个可选的最后手段策略。)

于 2011-05-05T15:03:47.290 回答
2

除此之外还有一个expireAfterWrite方法expireAfterAccess。这可能符合要求。

javadoc

指定自创建或替换条目后经过固定持续时间后,应自动从映射中删除每个条目。请注意,更改条目的值将重置其过期时间。

注意:expireAfterAccessexpireAfterWrite都是“实时的”,只是一个根据上次写入时间过期元素,另一个根据上次访问时间过期。

于 2011-05-05T14:30:55.557 回答
1

虽然 Dilum 的回答最有意义,但还要注意,使用自动驱逐的数据结构不一定会驱逐所有过期的条目。大多数到期发生在相对较小的批次中,因此,如果您有大量同时到期,您可能必须多次接触数据结构。不幸的是,我认为没有一种简单的编程方式可以可靠地做到这一点。

于 2011-05-28T06:13:00.983 回答