2013-04-15 37 views
4

我有一個使用案例,加載我的緩存數據的方法是批量調用,但我永遠不會使用getAll從緩存中獲取數據。有一種方法可以讓多個併發獲取單個loadAll上的所有塊嗎?我不希望個人獲得不同的密鑰,導致多次調用數據源。番石榴緩存 - 如何加載任何錯過?

cache.get(key1); // missing entry, starts refresh 
cache.get(key2); // separate thread, already getting reloaded due to key1 miss 

我想我要尋找到LocalCache,使用像在我的數據訪問本地緩存,只允許一個呼叫通過每一個時間使許多單位後,實現我自己的同步。通話結束後,使用單個賦值語句更新本地副本。

我錯過了什麼從番石榴的緩存庫嗎?

編輯:

我考慮像下面這樣。但是,它可能會繼續返回陳舊的數據,而loadAll完成。我更喜歡load的所有塊,只有第一個請求導致loadAll繼續。

public class DataCacheLoader extends CacheLoader<String, Double> 
{ 
    private final Cache<String, Double> cache; 
    private ConcurrentMap<String, Double> currentData; 
    private final AtomicBoolean isloading; 

    public DataCacheLoader(final Cache<String, Double> cache) 
    { 
     this.cache = cache; 
     isLoading = new AtomicBoolean(false); 
    } 

    @Override 
    public Double load(final String key) throws Exception 
    { 
     if (isLoading.compareAndSet(false, true)) 
     { 
      cache.putAll(loadAll(Lists.newArrayList(key)))); 
     } 
     return currentData.get(key); 
    } 

    @Override 
    public Map<String, Double> loadAll(Iterable<? extends String> keys) throws Exception 
    { 
     currentData = source.getAllData(); 
     return currentData; 
    } 
} 
+0

就像一個想法:調用get(K鍵,可贖回 valueLoader) ,並通過一個可調用,將調用LOADALL。 – kofemann

+0

也許用'ForwardingCache'做這個?不過,我會懷疑遞歸的'CacheLoader's。 –

+0

我想到了'ForwardingCache'方法。然而,對於具體的用例(這是一個泛化),我意識到我正在緩存在錯誤的粒度。如果我想要阻止整個負載,請緩存整個負載。我會留下這個問題,因爲我懷疑有一些用例阻止一切都可能有意義。 –

回答

8

下面是一個解決方案,應該做的伎倆。這個想法是,不是緩存每個單獨的密鑰,而是使用單個固定密鑰來緩存整個地圖。其中一個缺點是,你將無法使基礎地圖的各個部分失效(至少不容易),但這可能不是必需的。

class MyCache { 
    private static final Object KEY = new Object(); 
    private final LoadingCache<Object, Map<String, Double>> delegate = 
     new CacheBuilder() 
     // configure cache 
      .build(new CacheLoader<Object, Map<String, Double>>() { 
      public Map<String, Double> load(Object key) { 
       return source.load(); 
      } 
      }; 
    double get(String key) { 
    return cache.get(KEY).get(key); 
    } 
}