2013-07-26 42 views
1

我正在使用Guava緩存保留並定期刷新我們從長時間運行的數據庫查詢中收集的一些統計信息。我現在看到的問題是,所有線程都必須等待刷新,而不是讓調用者獲得過期的緩存值。在Guava緩存中有沒有辦法允許陳舊的讀取?番石榴緩存允許陳舊讀取?

緩存是建立這樣

cache = CacheBuilder.<DateType, List<DataValueEventQuality>> newBuilder() 
       .expireAfterWrite(cacheExpirySeconds, TimeUnit.SECONDS).build(); 

我使用cache.get(key, Callable)

+3

你如何刷新數據?從[documentation](http://code.google.com/p/guava-libraries/wiki/CachesExplained)_舊值(如果有的話)在密鑰刷新_時仍然返回。 –

+0

看到我的編輯更多的信息。 –

+0

你有沒有辦法使它成爲LoadingCache? –

回答

1

的緩存中檢索看來你使用的是此錯誤的方法。從documentation for LoadingCache有兩種方法:

void put(K key, V value) 

協會在此高速緩存鍵值。如果緩存先前的 包含與鍵相關聯的值,則舊值將替換爲 值。

這是原子,緩存必須等待。

void refresh(K key) 

荷載鍵鍵的新值,可能是異步的。雖然新 值加載先前值(如果有的話)將繼續由get(鍵)返回 ,除非它被逐出

你不說你用的是什麼樣的緩存或顯示任何代碼,所以我不知道你是否使用LoadingCache。但是,您需要使用refresh來緩存重新加載仍允許讀取舊值的值。

+0

如果新值加載並且舊值在內存中,則消耗的總內存將爲=新值內存+舊值內存。如果是這種情況,那麼不會導致程序用完堆內存?如果沒有,那麼你能告訴我這是如何避免? – prashant

+0

@prashant錯了。 –

+0

你能解釋爲什麼嗎? – prashant

1

是的,我知道這是老了,但我今天想通了這一點,所以繼承人的答案:從谷歌文檔採取:https://code.google.com/p/guava-libraries/wiki/CachesExplained#Refresh

關鍵部分是要refreshAfterWrite代替expireAfterWrite

// 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; 
      } 
     } 
     }); 
+0

在我的情況下,我發現後續問題,這種方法導致緩存雙重加載。你找到了解決這個問題的方法嗎? – ekitru