2011-11-05 260 views
14

當Guava的Tables.newCustomTable(Map, Supplier)方法提供線程安全映射時,會返回線程安全表嗎?例如:Guava Table線程安全嗎?

public static <R, C, V> Table<R, C, V> newConcurrentTable() { 
    return Tables.newCustomTable(
     new ConcurrentHashMap<R, Map<C, V>>(), 
     new Supplier<Map<C, V>>() { 
     public Map<C, V> get() { 
      return new ConcurrentHashMap<C, V>(); 
     } 
     }); 
} 

該代碼是否實際返回並發表?

+0

你對「並發表」的定義是什麼? –

+0

好問題。用另一種方式來解釋我的問題:這些表會不會以一種併發地圖>的方式炸燬?而通過「爆炸」,我的意思是進入無限循環,拋出異常,或者做任何其他常規HashBaseTable將做的事情,如果你試圖在多線程上同時讀取和寫入它。 –

回答

19

來自doc:「如果多個線程同時訪問此表,並且其中一個線程修改了表,則它必須在外部同步。」

併發備份集合是不夠的。

+0

奇怪的是,javadoc中的那句話促使我問這個問題。好吧。謝謝,凱文。 –

16

Kevin Bourrillion是對的。您構建的地圖不是線程安全的技術原因是,即使您使用的地圖是線程安全的,表操作也可能不是。讓我給放的例子,如StandardTable,這是使用Tables.newCustomTable實現:

public V put(R rowKey, C columnKey, V value) { 
    Map<C, V> map = backingMap.get(rowKey); 
    if (map == null) { 
    map = factory.get(); 
    backingMap.put(rowKey, map); 
    } 
    return map.put(columnKey, value); 
} 

線程安全的map == null案件處理損害。也就是說,兩個或更多個線程可以進入該塊併爲columnKey創建新條目,並且執行backingMap.put(rowKey, map)的最後一個將最終覆蓋backingMap中的columnKey的條目,這將導致丟失由其他執行的put操作線程。特別是在多線程環境下這種操作的結果是非確定性的,這相當於說這個操作不是線程安全的。

的正確實施此方法的是:

public V put(R rowKey, C columnKey, V value) { 
    ConcurrentMap<C, V> map = table.get(rowKey); 
    if (map == null) { 
     backingMap.putIfAbsent(rowKey, factory.get()); 
    } 
    map = backingMap.get(rowKey); 
    return map.put(columnKey, value); 
} 

我目前正在調查是否可以使用ForwardingTable實現與你想做的事一起,來獲得足夠的線程安全ConcurrentTable

但說實話,我認爲沒有線程安全的Table實現的原因是接口本身不提供任何併發結構,如putIfAbsentreplace

+1

在對StandardTable實現進行了大量瀏覽之後,我得出結論:爲了提供線程安全性,您只有兩個選擇:從頭開始創建實現,或者提供一個封裝來鎖定每個訪問。其原因是由row(),column()或columnMap()返回的視圖不是線程安全的,並且無法通過方法重寫來修改它們的行爲。 – velocipedist