Ehcache 是否使用删除过期项的后台线程?

Does Ehcache use a background thread that removes expired items?

我目前正在使用guava缓存,正在考虑迁移到Ehcache。根据这个 post 没有线程确保在番石榴缓存中的延迟结束后立即从缓存中删除条目:

Caches built with CacheBuilder do not perform cleanup and evict values "automatically," or instantly after a value expires, or anything of the sort. Instead, it performs small amounts of maintenance during write operations, or during occasional read operations if writes are rare.

The reason for this is as follows: if we wanted to perform Cache maintenance continuously, we would need to create a thread, and its operations would be competing with user operations for shared locks. Additionally, some environments restrict the creation of threads, which would make CacheBuilder unusable in that environment.

但是Ehcache呢?使用内存存储时是否有单独的线程删除过期的项目?找了资料,有人说没有,有人说有。

TLDR: Ehcache 不提供提示过期功能。 Guava 清理更迅速,但需要外部调度以保证粗粒度。 Caffeine 可以根据下一个到期事件安排清理。

Ehcache 依靠大小逐出来丢弃过期条目。这意味着当需要 space 时,尽管缓存中有许多过期的死条目,但活条目可能会被丢弃。由于 Ehcache 使用统一采样来发现逐出候选对象,因此它必须偶然发现死条目才能考虑将其删除。

在审查 Ehcache 2.x 和 3.x 的实现时,我的理解是,与活动条目相比,两者都更喜欢驱逐过期条目。抽样条目按其 lastAccessTime 字段排序,以便逐出最近最少使用的条目。如果过期时间不同,例如共享缓存同时保存短期 2FA 令牌和长期数据,那么在等待过期条目过期时可能会浪费大量 space。这种方法反映了 Memcached 和 Redis,但是由于它们非常大,这些缓存使用后台线程来主动查找和删除死条目。

Guava 在 O(1) 优先级队列上维护条目,以便它可以在维护期间删除过期的条目,例如在可能需要驱逐的写入之后。这只实现了固定的过期时间,这样一个条目就可以存储在一个双向链表中,并在恒定时间内重新排序到尾部位置。通过查看列表的头部,Guava 可以立即找到并删除过期的条目。正如@LouisWasserman 所建议的那样,定期调用 Cache.cleanUp() 可确保不活动的缓存将检查列表并丢弃过期的条目。不管怎样,缓存会根据读写定期进行维护activity.

Caffeine 通过支持 per-entry expiration and a scheduler to trigger cache maintenance based on the next expiration event. Variable expiration is implemented in O(1) time using a hierarchical timer wheel 扩展了这种方法。如果提供了调度线程,则调度任务将执行维护并导致过期条目被迅速驱逐。在 Java 9+ 中,JVM 包含一个专用的调度线程,如果配置为 Scheduler.systemScheduler().

,Caffeine 可以使用该线程
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
    .scheduler(Scheduler.systemScheduler())
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .build(key -> createExpensiveGraph(key));