如何使LoadingCache以非阻塞的方式调用load()



我正在使用谷歌的番石榴库来创建我的缓存。我将使用LoadingCache接口。下面是代码片段,

public class BlockedURLs {
private static final long MAX_SIZE = 1000;
private static final long CACHE_DURATION = 2;
private static LoadingCache<String, ArrayList<String> > lruBlockedURLCache;
BlockedURLs() {
    lruBlockedURLCache = CacheBuilder
            .newBuilder()
            .maximumSize(MAX_SIZE)
            .expireAfterWrite(CACHE_DURATION, TimeUnit.HOURS)
            .build(new CacheLoader<String, ArrayList<String>>() {
                @Override
                public ArrayList<String> load(String s) throws Exception {
                    return BlockedURLLoader.fetchBlockedURLListFromRedis(s);
                }
            });
}
public static ArrayList<String> getBlockedURLList(String domain) {
    return lruBlockedURLCache.getUnchecked(domain);
}
}

据我所知,如果我为没有缓存列表的域调用getBlockedURLList,它将首先加载列表,然后返回结果。但是,这不是我想要的行为。

如果密钥不在缓存中,我希望缓存调用它的加载函数,但我希望异步调用。所以,如果密钥不存在,我会说这次我可以在缓存中没有密钥的情况下工作,然后继续前进,但我希望下次尝试获取密钥时密钥存在。本质上,我想以非阻塞的方式调用load()。也就是说,cache.get()不应该等到首先从load()获取结果。

这是缓存解释中的示例

// Some keys don't need refreshing, and we want refreshes to be done asynchronously. 
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()        
   .maximumSize(1000)        
   .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 (neverNeedsRefresh(key)) {                  
            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;                
        }
          }
        });

在您的情况下,您可以选择从load()返回一个表示不存在的信号值,然后在后台填充缓存。

public Optional<List<String>> load(final Key key) {
    exec.submit(some-task-that-calls Cache.put(K,V));
    return Optional.absent();
}
LoadingCache<String,Optional<List<String>>> cache = ...

因此,在这种情况下,您可以通过立即提供信号值来绕过等待密钥可用的默认行为。当检索到URL时,任务应该调用Cache.put(K,V),使数据可用于后续调用。

您可以直接使用ConcurrentMap,尽管通过使用LoadingCache,每个键只能启动一个后台任务。

最新更新