2011-12-22 77 views
1

我有一個執行非常複雜的操作的對象的實例。如何使緩存線程安全

所以在第一種情況下我創建一個實例,並保存它,它自己的定製緩存。

從明年倍返還線程來,如果他發現有一個現成的對象已存在於他們把它從緩存中高速緩存,以便在性能良好的明智。

我很擔心如果兩個線程有​​什麼相同的實例。這兩個線程是否有可能互相腐蝕?

Map<String, SoftReference<CacheEntry<ClassA>>> AInstances= Collections.synchronizedMap(new HashMap<String, SoftReference<CacheEntry<ClassA>>>()); 
+0

緩存是否提交對其副本的引用,還是手抄送?線程如何將更改寫入緩存對象?這些寫入是否繞過緩存?如果是這樣,是否從高速緩存彈出數據,因爲高速緩存上的副本是陳舊的? – ArjunShankar 2011-12-22 15:09:30

+2

這將取決於您的緩存,請張貼您的代碼。 – 2011-12-22 15:10:20

+0

它不依賴於實例的線程安全嗎?你也可以同步訪問你的緩存,並且只允許一個線程訪問你的實例。 – 2011-12-22 15:12:07

回答

0

假設你正在談論單身,只需使用「demand on initialization holder idiom」,以確保您的「檢查」所有JVM的作品。這也將確保請求同一對象的所有線程併發地等待,直到初始化結束並且只返回有效的對象實例。

在這裏,我假設你想要的對象的單個實例。如果沒有,你可能想發佈一些更多的代碼。

0

有很多種可能的解決方案:

  • 使用像EHcache
  • 使用Spring框架,它有一個簡單的方法來一個方法的緩存結果用一個簡單的@Cacheable annotation
  • 使用一個現有的緩存解決方案提前像ConcurrentHashMap
  • 如果你知道所有的鍵同步地圖,你可以使用一個lazy init code。請注意,此代碼中的所有內容都是有原因的;在get()改變任何東西,它會打破最終(最終==「單元測試將運行,運行在生產一年不任何問題的任何後,將打破」)。

ConcurrentHashMap是最簡單的設置,但它有簡單的方式說「初始化鍵的值一次」。

不要試圖自己實現緩存; Java中的多線程已成爲Java 5以及多核CPU和內存障礙出現的一個非常複雜的領域。

[編輯]是的,這可能發生,即使地圖是同步的。例如:

SoftReference<...> value = cache.get(key); 
if(value == null) { 
    value = computeNewValue(key); 
    cache.put(key, value); 
} 

如果兩個線程同時運行這段代碼,computeNewValue()會被調用兩次。該方法調用get()put()是安全的 - 多個線程可以嘗試把在同一時間並沒有什麼大不了的事情,但是這並不能保護你從中產生的,當你調用連續幾種方法和的狀態問題地圖不得在它們之間改變。

0

好吧如果我正確理解你的問題,你擔心的是2個對象改變共享對象會破壞彼此的狀態。

簡短的回答是肯定的,他們會的。

如果該對象在創建過程中很昂貴,但需要以只讀方式。我建議你讓它不可變,這樣你就可以獲得快速訪問的好處,同時也是線程安全的。

如果狀態應該可寫,但實際上並不需要線程來查看其他每個更新。您只需將對象加載到不可變的緩存中,然後將副本返回給請求該對象的任何人。

最後,如果您的對象需要可寫和共享(由於其他原因,而不是創建昂貴)。然後我的朋友你需要處理線程安全性,我不知道你的情況,但你應該看看synchronized關鍵字,Locks和Java 5併發特性,Atomic類型。我相信,他們中的一個將滿足您的需求,我衷心祝願你的情況是第2 :)