2012-10-05 89 views
5

我的用例是在持久數據庫中存儲的數據上維護內存中高速緩存。在Java中實現定期刷新高速緩存

我用數據來填充的UI項的列表/地圖。在任何時候,UI上顯示的數據應該儘可能更新(這可以通過緩存的刷新頻率來完成)。常規的緩存實現這個特定的緩存之間

主要區別在於,它需要定期的所有元素的批量刷新,因此是從LRU一種高速緩存的有很大不同。

我需要做在Java中這種實現,如果有可利用來得到這個圍繞他們所建立的任何現有的框架也將是巨大的。

我已經探索了谷歌番石榴緩存庫,但它更適合於每個條目刷新,而不是批量刷新。沒有簡單的API在整個緩存中進行刷新。

任何幫助將不勝感激。另外,如果可以遞增地進行刷新,它應該是很棒的,因爲刷新整個緩存時出現的唯一限制是如果緩存非常大,那麼內存堆至少應該是兩次緩存的大小,以加載新的條目,並用新的地圖替換舊的地圖。如果緩存是增量式的,或者存在分塊刷新(以相同大小刷新),那將會很好。

回答

3

EHCache是一個漂亮的全功能的Java緩存庫實現loadDataFromDB和了updateData。我會想象他們有什麼能爲你工作。

爲了做一個緩存的增量重載(這將在幾乎所有的緩存使用),只是通過當前加載項迭代和力刷新它們。 (你可以在後臺調度器上運行這個任務)。

作爲強制整個緩存重新加載的替代方法,EHCache可以爲條目指定「生存時間」,因此如果條目過舊,條目將自動重新加載。

+1

@ jtahlborn - EhCache的BulkLoader API(http://ehcache.org/documentation/apis/bulk-loading)很有幫助,但如果它提供了一個refreshTime或週期性間隔時間選項,它本身可以管理它高速緩存刷新的調度。無論如何,它總是可以通過外部調度程序並定期調用批量加載API來實現。感謝你的回答。 –

+0

對於EHCache,請參閱:http://www.ehcache.org/documentation/3.3/thread-pools.html和http://terracotta.org/documentation/4.1/bigmemorymax/api/bulk-loading – Aliuk

+0

但是。 .sn't生存時間只是從緩存中刪除元素?它和你在這裏寫的不一樣 - 「自動重新加載」 – javagirl

0

只是繼承這個類,併爲你想要得到的incremential更新

import org.apache.log4j.Logger; 
import java.util.List; 
import java.util.concurrent.Semaphore; 


public abstract class Updatable<T> 
{ 
    protected volatile long lastRefreshed = 0; 
    private final int REFRESH_FREQUENCY_MILLISECONDS = 300000; // 5 minutes 
    private Thread updateThread; 
    private final Semaphore updateInProgress = new Semaphore(1); 

    protected static final Logger log = Logger.getLogger(Updatable.class); 

    public void forceRefresh() 
    { 
     try 
     { 
      updateInProgress.acquire(); 
     } 
     catch (InterruptedException e) 
     { 
      log.warn("forceRefresh Interrupted"); 
     } 

     try 
     { 
      loadAllData(); 
     } 
     catch (Exception e) 
     { 
      log.error("Exception while updating data from DB", e); 
     } 
     finally 
      { 
      updateInProgress.release(); 
     } 

    } 

    protected void checkRefresh() 
    { 
     if (lastRefreshed + REFRESH_FREQUENCY_MILLISECONDS <  System.currentTimeMillis()) 
      startUpdateThread(); 
    } 

    private void startUpdateThread() 
    { 
     if (updateInProgress.tryAcquire()) 
     { 
      updateThread = new Thread(new Runnable() 
      { 
       public void run() 
       { 
        try 
        { 
         loadAllData(); 
        } 
        catch (Exception e) 
        { 
         log.error("Exception while updating data from DB", e); 
        } 
        finally 
        { 
         updateInProgress.release(); 
        } 
       } 
      }); 

      updateThread.start(); 
     } 
    } 

    /** 
    * implement this function to load the data from DB 
    * 
    * @return 
    */ 
    protected abstract List<T> loadFromDB(); 

    /** 
    * Implement this function to hotswap the data in memory after it was loaded from DB 
    * 
    * @param data 
    */ 
    protected abstract void updateData(List<T> data); 

    private void loadAllData() 
    { 
     List<T> l = loadFromDB(); 
     updateData(l); 
     lastRefreshed = System.currentTimeMillis(); 
    } 

    public void invalidateCache() 
    { 
     lastRefreshed = 0; 
    } 

} 
+0

感謝您的答案RA。 什麼時候會調用checkRefresh()函數?如果我理解正確,這將需要一個連續運行的進程來定期使用checkRefresh進行輪詢。我期待着一個更清晰的實現,我可以用一個緩存加載器來插入一個新的緩存。 –

+0

應該在您在課堂上實施的每個獲取操作中調用CheckRefresh。一世。E:public Data get(){checkRefresh(); //返回數據; } –

+0

但是這會影響更新線程被觸發時數據檢索的延遲,就好像它已經像cron一樣前進了,並且已經預取了數據,這種情況就不會出現。 –

0

必須檢查的一件事是定期刷新需要?一旦從高速緩存中獲取數據,就可以應用刷新邏輯,這將消除對任何異步刷新的需要,並且不需要維護高速緩存的任何舊副本。這是IMO最簡單也是最好的刷新緩存數據的方式,因爲它不涉及任何額外的開銷。

T getData(){ 
     // check if the last access time + refresh interval >= currenttime if so then refresh cache 
    // return data 
    } 

這將確保數據基於刷新間隔進行刷新,並且不需要任何異步刷新。