定时缓存过期如何工作?

时间:2016-08-31 12:46:41

标签: guava google-guava-cache

我知道Guava Cache允许为个人缓存配置一个到期时间。 Guava是否使用在配置的秒数后唤醒的计时器来使缓存失效?

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

谢谢,
佳日

1 个答案:

答案 0 :(得分:2)

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

  

使用CacheBuilder构建的缓存执行清理并逐出值   “自动”,或在值到期后立即或任何其他内容   那种。相反,它在执行期间执行少量维护   写入操作,或者在写入时偶尔进行读取操作   罕见的。

     

原因如下:如果我们想要执行Cache   维护不断,我们需要创建一个线程,它的   操作将与共享锁的用户操作竞争。   此外,某些环境限制线程的创建,   这将使CacheBuilder在该环境中无法使用。

     

相反,我们将选择权交给您。如果您的缓存是   高吞吐量,那么你不必担心执行缓存   维护以清理过期的条目等。如果你的缓存   写入很少,你不希望清理阻止缓存   读取,您可能希望创建自己的调用维护线程   Cache.cleanUp()定期。{/ p>      

如果要为缓存安排常规缓存维护   只有很少写入,只需使用安排维护   ScheduledExecutorService

因此,如果您只是在阅读时,如果您在交易之前和之后进行Cache.cleanUp(),那么“可能”会很好,但仍无法保证。

但是,不是试图强制项目留在缓存中,而是使用removalListener简单地将项目驱逐到另一个缓存/地图,然后在阅读时首先需要检查缓存,然后,如果不存在,请检查长期交易中被驱逐的物品。

以下是一个过于简单的例子:

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");

您的实际代码需要有条件地put进入evicted,清理evicted,如果您同时运行长时间运行的事务或管理多个evicted对象具有不同驱逐策略的线程之间的公共缓存等等,但希望这充分证明了这个想法可以帮助您入门。