2009-07-19 74 views
1

有更好的方法來緩存一些只能創建一次的非常大的對象,因此需要緩存嗎?目前,我有以下幾點:關於使用基於Enum的Singleton來緩存大對象(Java)

public enum LargeObjectCache { 
    INSTANCE; 

    private Map<String, LargeObject> map = new HashMap<...>(); 

    public LargeObject get(String s) { 
     if (!map.containsKey(s)) { 
      map.put(s, new LargeObject(s)); 
     } 
     return map.get(s); 
    } 
} 

有幾類,可以使用LargeObjects,這就是爲什麼我決定使用一個單獨的緩存,而不是傳遞LargeObjects到使用它的每一個類。

此外,地圖不包含許多密鑰(一個或兩個,但密鑰可以在程序的不同運行中有所不同),那麼,在這種情況下是否有另一個更高效的地圖?

回答

4

您可能需要線程安全性以確保您沒有兩個相同名稱的實例。 對於小地圖來說確實很重要,但是您可以避免一次可以使其更快的呼叫。

public LargeObject get(String s) { 
    synchronized(map) { 
     LargeObject ret = map.get(s); 
     if (ret == null) 
      map.put(s, ret = new LargeObject(s)); 
     return ret; 
    } 
} 
+0

你是對的,謝謝。然而,在javadoc中,它提到了線程安全性:「這通常是通過同步某個自然封裝地圖的對象來完成的,如果不存在這樣的對象,則應該使用Collections.synchronizedMap方法「。 那麼,使用synchronized(map)和使用Collections.synchronizedMap(map),甚至使用ConcurrentHashMap 之間有什麼區別呢?他們似乎都有相同的目標,但我想一定有差異。 – 2009-07-19 12:09:22

2

正如已經指出的那樣,您需要解決線程安全問題。只需使用Collections.synchronizedMap()並不能完全正確,因爲代碼需要複合操作。同步整個塊是一個解決方案。但是,如果使用ConcurrentHashMap,它會產生更多併發和可伸縮的行爲。

public enum LargeObjectCache { 
    INSTANCE; 

    private final ConcurrentMap<String, LargeObject> map = new ConcurrentHashMap<...>(); 

    public LargeObject get(String s) { 
     LargeObject value = map.get(s); 
     if (value == null) { 
      value = new LargeObject(s); 
      LargeObject old = value.putIfAbsent(s, value); 
      if (old != null) { 
       value = old; 
      } 
     } 
     return value; 
    } 
} 

您需要在此表單中正確使用它才能獲得正確和最有效的行爲。

如果您必須確保只有一個線程可以實例化給定鍵的值,那麼就有必要轉向Google Collections中的計算映射或Brian Goetz的書「實踐中的Java併發性」中的memoizer示例」。