2014-09-22 77 views
1

我有線程A,插入一個新的元素番石榴緩存,而且由於尺寸的政策,緩存將驅逐與關鍵Y.番石榴緩存,如何阻止訪問,同時做切除

遺憾的是,相關的元素Y的去除過程R需要很長時間,並且在Y正在由R處理的過程中(已經被驅逐但仍然在R中),還有另一個線程B試圖獲得與關鍵字Y相關的數據。

基本上,R將嘗試要更新關鍵字Y的數據庫,並且在該值未更新時,線程B嘗試訪問數據庫以獲取與鍵Y相關的值,該值仍舊是舊值。

問題是:當R正在做它的工作時,如何阻止線程B通過鍵Y訪問元素?

回答

3

你說過Guava Cache,但沒有代碼示例,所以我給出了一個普遍的答案。

對於下面我假設你有一個「加載緩存」又名「自填充緩存」模式。

解決方案1: 正確設計緩存交互和數據庫事務。

更新過程使緩存條目無效,只要在其上啓動事務即可。

begin transaction 
    touch some of the entry data with SQL UPDATE to have it in the transaction 
    remove the entry from the cache 
    .... 
    now you can do more operations on the database regarding the entry data 
    if you have the proper isolation level, reads from the database will stall 
    until the transaction is committed 
    .... 
    end transaction 

如果您從緩存中刪除條目,然後啓動事務,則會引入競爭條件。

解決方案2: 使用高速緩存阻止同一鍵/條目上的併發操作。

看一下ehcache Blocking Cache。或者查看cache2k,其中阻止行爲是默認行爲。

但是,您需要自己額外鎖定加載器級別。例如。如下面的例子。

解決方案3: 自行鎖定在緩存頂部幷包裝所有緩存操作。例如。類似於:

Cache cache; 
Lock[] locks = new Lock[16]; 
{ /* initialize locks */ } 

public Object get(Object key) { 
    int idx = key.hashCode() % locks.length; 
    locks[idx].lock(); 
    try { return cache.get(key); 
    } finally { locks[idx].unlock(); } 
} 

public void update(Object key, Object obj) { 
    int idx = key.hashCode() % locks.length; 
    locks[idx].lock(); 
    try { return cache.put(key, obj); 
    } finally { locks[idx].unlock(); } 
} 

您還可以查看ehcache中的BlockingCache實現,並從中獲取靈感。

玩得開心!

+0

我不確定,但恐怕您錯過了*「如果您從緩存中刪除條目然後...」*,因爲刪除自動發生。我不知道Guava緩存是否立即調用'RemovalListener'。無論如何,你最後的解決方案似乎涵蓋了一切。 – maaartinus 2014-09-24 18:18:16

+0

我和maartinus有同樣的評論,解決方案3似乎是一個很好的解決方案。 – user3714348 2014-09-25 10:51:39