2014-09-23 47 views
14

在ConcurrentHashMap(put(),remove()等)上執行所有非retreival操作是否需要封裝在synchronized(this)塊中?我知道所有這些操作都是線程安全的,那麼這樣做有沒有真正的好處/需要?唯一使用的操作是put()remove()ConcurrentHashMap需要包裝在同步塊中嗎?

protected final Map<String, String> mapDataStore = new ConcurrentHashMap<String, String>(); 

public void updateDataStore(final String key, final String value) { 
    ... 
    synchronized (this) { 
     mapDataStore.put(key, value); 
    } 
    ... 
} 

回答

35

不,您正在失去ConcurrentHashMap的好處。您也可以被使用與​​或synchronizedMap()一個HashMap鎖定整個表(這是你做什麼,在​​包裝操作時,因爲隱含的顯示器是整個對象實例。)

ConcurrentHashMap目的是通過允許併發讀取/寫入表而不鎖定整個表來增加併發代碼的吞吐量。該表通過使用鎖定條帶化(多個鎖而不是一個,其中每個鎖分配給一組散列桶 - 參見Goetz等的Java Concurrency in Practice)來在內部支持這一點。

一旦你正在使用ConcurrentHashMap,(put()remove()等)成爲藉助於鎖條帶化等在執行的原子的所有標準地圖的方法。唯一的折衷是像size()isEmpty()這樣的方法可能不一定會返回準確的結果,因爲它們唯一可能的方式是鎖定整個表的所有操作。

ConcurrentMap interface接口還增加了新的原子複合操作,如putIfAbsent()(放東西,只有當它的關鍵是不是已經在地圖),remove()接受兩個鍵和值(僅刪除其值等於你傳遞參數的條目)等。這些操作用於需要鎖定整個表格,因爲它們需要兩個方法調用來完成(例如,如果您使用的是標準Map實現,則putIfAbsent()需要調用containsKey()put(),封裝在一個​​塊中。)一次再次,通過避免鎖定整個表,您可以使用這些方法獲得更高的吞吐量。

6

同步這些操作在這裏沒有任何好處 - 如果您不需要同步,它實際上會降低性能。

創建ConcurrentHashMap的原因是,當許多線程訪問時,同步映射(無論是通過手工方式在問題中實現,還是以通常的方式與Collections.synchronizedMap(map)實例化)都表現不佳。放置並獲取操作是阻塞的,因此所有其他線程必須等待並且不能併發訪問地圖。另一方面,ConcurrentHashMap - 顧名思義 - 允許併發訪問。如果添加同步,則會失去此優勢。

相關問題