Guava CacheBuilder 不清除缓存

Guava CacheBuilder not clearing cache

我将 CacheBuilderexpireAfterWrite(2000, TimeUnit.Milliseconds) 一起使用。我向我的程序发送了 10000 个请求,我希望 CacheBuilder 在每个请求 2 秒后调用 RemovalListener 10000 次。我没有观察到这种行为,而是 RemovalListener 被调用了 1 或 2 次。

有人可以向我解释一下 CacheBuilder 正在做什么吗,因为正如我上面解释的那样,它正在做的事情与 Guava 提供的文档完全不同。

本着与上述相同的精神,我使用 maximumSize(1000) 并在向我的程序发送 10000 个请求后,我希望 RemovalListener 被调用 9000 次。但它只被调用了1或2次。

这个模块在现实中是如何工作的?

编辑

我每次收到请求时都会明确调用 clean cleanup

removal behavior is documented 并按预期工作(强调我的):

When Does Cleanup Happen?

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.

Instead, we put the choice in your hands. If your cache is high-throughput, then you don't have to worry about performing cache maintenance to clean up expired entries and the like. If your cache does writes only rarely and you don't want cleanup to block cache reads, you may wish to create your own maintenance thread that calls Cache.cleanUp() at regular intervals.

如果你想对缓存有更多的控制,并有专门的执行器来照顾调用 RemovalListeners,使用 Caffeine -- a high performance, near optimal caching library based on Java 8 -- which has an API similar to Guava's Cache (same author). Caffeine has more advanced removal handling:

You may specify a removal listener for your cache to perform some operation when an entry is removed, via Caffeine.removalListener(RemovalListener). The RemovalListener gets passed the key, value, and RemovalCause.

Removal listener operations are executed asynchronously using an Executor. The default executor is ForkJoinPool.commonPool() and can be overridden via Caffeine.executor(Executor). When the operation must be performed synchronously with the removal, use CacheWriter instead.