定时缓存过期如何工作?

How does timed cache expiry work?

我知道 Guava Cache 允许为单个缓存配置过期时间。 Guava 是否使用在配置的秒数后唤醒以使缓存无效的计时器来执行此操作?

我有一个多头交易-运行。无论事务开始时缓存中有什么,我都希望它一直持续到事务结束。因此,即使缓存的有效秒数在事务期间过期,从缓存访问的值也应该保持不变,直到我们到达事务结束。这在番石榴中可能吗?

谢谢,
亚什

来自 When Does Cleanup Happen? · CachesExplained · google/guava Wiki:

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.

If you want to schedule regular cache maintenance for a cache which only rarely has writes, just schedule the maintenance using ScheduledExecutorService.

因此,如果您只进行读取操作,"might" 如果您在交易前后进行 Cache.cleanUp() 操作会更好,但仍然无法保证。

但是,与其尝试强制项目保留在缓存中,不如使用 removalListener 简单地将项目驱逐到另一个 cache/map,然后当您阅读时,您首先需要检查缓存,然后,如果它不存在,则检查在长期 运行 事务期间逐出的项目。

以下是一个过度简化的示例:

Map<Integer, String> evicted = new ConcurrentHashMap<>();
Cache<Integer, String> cache = CacheBuilder.newBuilder()
        .expireAfterAccess(2, SECONDS)
        .removalListener((RemovalListener<Integer, String>) notification -> 
                evicted.put(notification.getKey(), notification.getValue()))
        .build();
assert evicted.size() == 0 && cache.size() == 0;
cache.put(0, "a");
cache.put(1, "b");
cache.put(2, "c");
assert evicted.size() == 0 && cache.size() == 3;
sleepUninterruptibly(1, SECONDS);
assert evicted.size() == 0 && cache.size() == 3;
cache.put(3, "d");
assert evicted.size() == 0 && cache.size() == 4;
sleepUninterruptibly(1, SECONDS);
cache.cleanUp();
assert evicted.size() == 3 && cache.size() == 1;
Integer key = 2;
String value;
{
    value = cache.getIfPresent(key);
    if (value == null) value = evicted.get(key);
}
assert Objects.equals(value, "c");

如果您的 运行 长- 运行 并发事务或在具有不同逐出策略的线程之间使用公共缓存等,但希望这足以证明这个想法,让您入门。