2016-01-22 142 views
2

我想澄清一些關於ConcurrentHashMap vs ConcurrentSkipListMap的API文檔。ConcurrentHashMap vs ConcurrentSkipListMap澄清

從我的理解ConcurrentHashMap gaurantees線程安全的多線程插入。所以如果你有一個只能被多個線程併發填充的地圖,那麼就沒有問題了。然而,API繼續建議它不保證檢索的鎖定,所以你可能會在這裏得到誤導結果?

相比之下,ConcurrentSkipListMap聲明:「插入,刪除,更新和訪問操作安全地由多個線程同時執行」。所以我認爲這沒有前面提到的哈希映射的檢索問題,但顯然這通常會帶來性能成本?

實際上,有沒有人發現需要使用ConcurrentSkipListMap是因爲這種特殊的行爲,或者一般來說沒有關係,檢索可能會提供過時的視圖?

回答

2

ConcurrentHashMap

反演反映最近完成的更新 操作拿着在他們發病的結果。對於彙總操作(如 )putAll和clear,併發檢索可能反映插入或僅刪除一些條目。

它使用易失性語義get(key)。當Thread1呼叫put(key1, value1)並緊接着Thread2呼叫get(key1)時,Thread2不會等待Thread1完成它的put,它們不會彼此同步,並且Thread2 可以獲得舊的關聯值。但是,如果put(key1, value1)在Thread1嘗試到get(key1)之前在Thread1中完成,那麼Thread2將保證獲得此更新(value1)。

ConcurrentSkipListMap進行排序,並提供

預期平均log(n)的時間成本,爲containsKey方法,獲取 put和remove操作及其變體

ConcurrentSkipListMap沒有那麼快,但在需要排序的線程安全映射時非常有用。

+0

如果您想要獲取最新的副本,那麼您通常會如何處理這個問題 - 有沒有辦法使用不同的數據結構,或者使用ConcurrentHashMap來處理阻塞? – Tranquility

+0

實際上,在所有情況下'ConcurrentHashMap'就夠了。對我來說,更新意味着能夠看到完整的更新 - 而且它在'ConcurrentHashMap'中是如此。但是如果你想在put開始時立即阻止所有的地圖獲取,那麼你有一些額外的同步。您可以使用效率低下的Collections.synchronizedMap()或者具有相應關聯的ReadWriteLocks的嚴格大小的HashMap數組(像ConcurrentHashMap中的段)。請注意,這種阻塞幾乎總是不必要的,並會影響性能。真誠的我無法想象什麼時候你需要它。 – dezhik

1

但是,API繼續暗示它不保證檢索的鎖定,因此您可能會在這裏獲得誤導性結果?

有趣的是,ConcurrentSkipListMap,事實上CSLM也是完全非阻塞的。

在Java 7中對於所有意圖和目的,CHM在執行讀取時是非阻塞的。實際上,Java 8的更新的CHM實現具有完全無阻塞的讀取。

這裏的要點是CHM和CSLM具有相似的讀取語義,區別在於時間複雜度。

+0

那麼爲什麼API會這樣說:「插入,刪除,更新和訪問操作安全地由多個線程同時執行。」 ...? – Tranquility

+0

因爲不會出現更新操作的競爭條件,所以他們使用'ReentrantLock'來進行相互同步。並且根據推測,所有完成的更新應該對獲取可見 - 它的工作原理正如在讀取時所說的那樣。 – dezhik

+1

@Tranquility只是因爲算法不是阻塞並不意味着它是線程不安全的。有像'ConcurrentLinkedQueue'這樣的完全線程安全的非阻塞併發算法。 CHM使用阻塞和非阻塞讀取/寫入的組合來確保線程安全。 –

0

從你的問題,你似乎得出結論,只有插入到ConcurrentHashMap線程安全。

從我的理解ConcurrentHashMap gaurantees線程安全插入由多個線程。所以如果你有一個只能被多個線程併發填充的地圖,那麼就沒有問題了。

你是如何得出這個結論的? ConcurrentHashMap的文檔的第一行意味着所有操作都是線程安全的:

支持完全併發檢索和可調整預期併發更新的哈希表。

此外,這意味着get()操作可以維持比put()操作更高級別的併發性。

簡單地說,ConcurrentHashMap沒有您認爲它具有的檢索問題。在大多數情況下,您應該使用ConcurrentHashMap而不是ConcurrentSkipListMap,因爲ConcurrentHashMap的性能通常優於ConcurrentSkipListMap。當您需要具有可預測的迭代順序的ConcurrentMap或者需要NavigableMap的設施時,您應該只使用CurrentSkipListMap