目前的地图驱逐算法非常懒惰。看起来只有在访问数据结构时才会驱逐过期的对象。
例如,从地址到索引器的映射定义为:
ConcurrentMap<Address, Indexer> indexers = new MapMaker()
.expireAfterAccess( EXPIRATION, TimeUnit.SECONDS)
.evictionListener( new IndexEvicted())
.makeMap();
导致了相当令人惊讶的模式:虽然给定地址的containsKey()
返回false,但在该地址的索引器被驱逐之后立即返回。
建议的方法是什么使清理过程更加实时?即删除接近实际到期时间的对象。
更新:我想通过实时更清楚地说明我的意思。对于上面的示例,EXPIRATION为10秒,我希望看到插入的对象在上次访问后10秒内被逐出。现在没有发生 - 必须以某种方式使用地图来开始驱逐。如果地图完全未使用,则该对象可以在那里停留多年。
答案 0 :(得分:4)
为了及时驱逐,Guava需要实现某种后台线程或定时重复任务。这样做会使地图变得更加沉重,并且更难以在J2EE或环境中使用,在这些环境中,安全策略会阻止线程无法生成。
如果您关心及时驱逐,请设置您自己的触摸地图的定时线程。
另一方面,我同意让垃圾收集器触发驱逐会很好......例如使用SoftReference和终结器。 (是的,我知道终结者大多是邪恶的,我只是建议一个可选的最后策略。)
答案 1 :(得分:2)
除了expireAfterWrite
之外,还有一个expireAfterAccess
方法。这可能符合法案。
来自javadoc:
指定自条目创建或替换后经过固定的持续时间后,应自动从地图中删除每个条目。请注意,更改条目的值将重置其到期时间。
注意:expireAfterAccess
和expireAfterWrite
都是“实时”,只是一个根据上次写入时间到期,另一个是基于上次访问时间。
答案 2 :(得分:1)
虽然Dilum的答案最有意义,但同时请注意,触摸自动驱逐的数据结构不必然会驱逐所有过期的条目。大多数到期发生在相对较小的批次中,因此,如果您有大量的同时到期,您可能需要多次触摸数据结构。不幸的是,我认为没有一种简单的编程方式可靠地完成这项工作。