41

我正在使用 Google Guava 库进行缓存。对于自动缓存刷新,我们可以执行以下操作:

cache = CacheBuilder.newBuilder()               
                    .refreshAfterWrite(15, TimeUnit.MINUTES)
                    .maximumSize(100)
                    .build(....);

但是,当第一次出现对条目的陈旧请求时,会执行自动刷新

即使没有请求缓存数据,有没有办法自动刷新它?就像每 15 分钟应该从 Db 中提取缓存数据并加载它,无论是否有人调用缓存数据。

此外,Guava 的缓存到期时间是针对整个缓存的。是否可以根据键使缓存值过期?就像键为“NOT_SO_FREQ_CHANGE_DATA”的缓存数据每 1 小时过期一次,而键为“FREQ_CHANGING_DATA”的数据应该每 15 分钟过期一次?

4

5 回答 5

32

Guava 没有提供批量刷新缓存的方法,但您可以自己安排定期刷新:

LoadingCache<K, V> cache = CacheBuilder.newBuilder()
        .refreshAfterWrite(15, TimeUnit.MINUTES)
        .maximumSize(100)
        .build(new MyCacheLoader());

for (K key : cache.asMap().keySet()) {
    cache.refresh(key);
}

但在这种情况下,您可能希望覆盖其中的CacheLoader.reload(K, V)方法,MyCacheLoader以便它异步执行。

至于第二个问题,不,你不能在 Guava 中设置 per-entry 到期。

于 2012-07-13T08:30:16.540 回答
11

JAVA 8 version with parallel stream:

Executors
        .newSingleThreadScheduledExecutor()
        .scheduleWithFixedDelay(() -> configurationCache
                .asMap()
                .keySet()
                .parallelStream()
                .forEach((key) -> configurationCache.refresh(key)),
            0,
            1, TimeUnit.SECONDS);
于 2017-03-24T09:18:56.700 回答
9

第一个问题。使用计划的执行程序启动定期刷新。

第二个问题。如果您可以从缓存键或先前缓存的值中推断出您的过期策略,则可以以不同的时间间隔刷新您的数据。

based on this: https://code.google.com/p/guava-libraries/wiki/CachesExplained#Refresh

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
   .refreshAfterWrite(1, TimeUnit.MINUTES)
   .build(
       new CacheLoader<Key, Graph>() {
         public Graph load(Key key) { // no checked exception
           return getGraphFromDatabase(key);
         }

         public ListenableFuture<Graph> reload(final Key key, Graph prevGraph) {
           if (!needsRefresh(key,prevGraph)) {
             return Futures.immediateFuture(prevGraph);
           } else {
             // asynchronous!
             ListenableFutureTask<Graph> task = ListenableFutureTask.create(new Callable<Graph>() {
               public Graph call() {
                 return getGraphFromDatabase(key);
               }
             });
             executor.execute(task);
             return task;
           }
         }
       });

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleWithFixedDelay(
    new Runnable() {
        public void run() {
            for (Key key : graphs.asMap().keySet()) {
                graphs.refresh(key);
            }
        }
    }, 0, UPDATE_INTERVAL, TimeUnit.MINUTES);
于 2013-10-16T17:41:37.357 回答
4

Can you reload the cache value automatically using the below code snippet, without calling the refresh method ??

cacher =
        CacheBuilder.newBuilder()
            .refreshAfterWrite(10, TimeUnit.SECONDS)
          .build(CacheLoader.asyncReloading(new CacheLoader<String, String>() {

              @Override
              public String load(String key) throws Exception {
                return method-call();
              }
            }, Executors.newSingleThreadExecutor()));
于 2020-03-31T04:23:33.510 回答
-3

Here is some sample code to refresh a cache. Guava cache is easy to implement and also it is fast.

import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

public class GuavaTest {
    private static GuavaTest INSTANCE = new GuavaTest();

    public static GuavaTest getInstance(){
        return INSTANCE;
    }   

    private LoadingCache<String,String> cache;

    private GuavaTest() {
        cache = CacheBuilder.newBuilder()
                .refreshAfterWrite(2,TimeUnit.SECONDS)
                .build(new CacheLoader<String, String>() {
                        @Override
                        public String load(String arg0) throws Exception {
                            return addCache(arg0);
                        }
                });
    }

    private String addCache(String arg0) {
        System.out.println("Adding Cache");
        return arg0.toUpperCase();
    }

    public String getEntry(String args) throws ExecutionException{
        System.out.println(cache.size());
        return cache.get(args);
    }

    public static void main(String[] args) {
        GuavaTest gt = GuavaTest.getInstance();
        try {
            System.out.println(gt.getEntry("java"));
            System.out.println(gt.getEntry("java"));
            Thread.sleep(2100);
            System.out.println(gt.getEntry("java"));
            System.out.println(gt.getEntry("java"));
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

I referred this article guava cache example

于 2015-11-18T17:44:32.537 回答