我需要一个在键值对过期后运行一段代码的数据结构。例如,我有一个密钥和一个连接对象存储在即将过期的哈希图中。我需要这个过期的哈希图来运行一个函数,该函数将 connObj 作为参数,并在键值对过期后关闭连接。
我已经探索了 Apache 的 PassiveExpiringMap 和 Google 的 Guava.MapMaker,但我没有看到任何清理功能,有人知道有什么方法可以做到这一点吗?
正如 @BenManes 在评论(Caffeine 的创建者)中提到的,请参阅 https://github.com/ben-manes/caffeine/wiki/Cleanup 中的示例(重点是我的):
默认情况下,Caffeine 不会“自动”或在值过期后立即执行清理和逐出值。相反,它会在写入操作后执行少量维护工作,或者如果写入很少,则偶尔在读取操作后执行少量维护工作。如果您的缓存是高吞吐量的,那么您不必担心执行缓存维护来清理过期的条目等。 如果您的缓存很少被读写,您可能希望利用外部线程,如下所述,在适当的时候调用
。
Cache.cleanUp()
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder() .scheduler(Scheduler.systemScheduler()) .expireAfterWrite(10, TimeUnit.MINUTES) .build(key -> createExpensiveGraph(key));
可以提供调度程序来快速删除过期条目。过期事件之间的调度是利用批处理并最大限度地减少短时间连续执行的。 调度是尽力而为的,并且不会对何时删除过期条目做出任何硬性保证。 Java 9+ 用户可能更喜欢使用
来利用专用的系统范围调度线程。
Scheduler.systemScheduler()
Caffeine#scheduler(Scheduler)
javadoc中找到:
过期事件之间的调度是为了利用批处理并最大限度地减少短时间连续执行。 计划执行之间的最小差异是特定于实现的,目前约为 1 秒 (2^30 ns)。此外,所提供的调度程序可能无法提供实时保证(包括
)。该调度是尽力而为的,并且不会对何时删除过期条目做出任何硬性保证。ScheduledThreadPoolExecutor
因此,如果 Caffeine 中的调度程序实现方式适合您,那么您应该可以很好地使用
removalListener
(或 evictionListener
),例如。使用上面示例代码中的类型:
.removalListener((Key key, Graph graph, RemovalCause cause) ->
yourFunction(connObj, key, graph, cause)) // or whatever you need
经过探索,我发现 Jodah 的这个过期哈希图非常有用 - https://jodah.net/expiringmap/javadoc/net/jodah/expiringmap/ExpiringMap.html
数据结构使用异步过期监听器。我的实现是这样的
Map<String, Connections> ConnMap = ExpiringMap.builder()
.maxSize(100000)
.expiration(30, TimeUnit.MINUTES)
.expirationPolicy(ExpirationPolicy.ACCESSED)
.expirationListener((key, connObject) -> {
System.out.println("Closing connObject->key: " + key + " connObj: " + connObject);
connObject.close();
})
.build();