如何使用Google Guava自动刷新缓存?

时间:2012-07-13 03:21:09

标签: java caching guava

我正在使用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分钟到期一次?

5 个答案:

答案 0 :(得分:25)

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

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

关于第二个问题,不,你不能在番石榴中设置每个条目的到期日。

答案 1 :(得分:6)

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

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

基于此: 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);

答案 2 :(得分:5)

带并行流的JAVA 8版本:

Executors
        .newSingleThreadScheduledExecutor()
        .scheduleWithFixedDelay(() -> configurationCache
                .asMap()
                .keySet()
                .parallelStream()
                .forEach((key) -> configurationCache.refresh(key)),
            0,
            1, TimeUnit.SECONDS);

答案 3 :(得分:1)

是否可以使用下面的代码片段自动重载缓存值,而无需调用刷新方法?

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

答案 4 :(得分:-1)

以下是一些刷新缓存的示例代码。番石榴缓存易于实现,而且速度快。

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();
        }
    }

}

我参考了这篇文章guava cache example