Collections.synchronizedMap與ConcurrentHashMap
1.概述
在本教程中,我們將討論[Collections.synchronizedMap()](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collections.html#synchronizedMap(java.util.Map))
和ConcurrentHashMap
之間的區別.
另外,我們將查看每個讀寫操作的性能輸出。
2.差異
Collections.synchronizedMap()
和ConcurrentHashMap
都提供對數據集合的線程安全操作。
Collections
實用程序類使用了多態算法對集合進行操作並返回包裝後的集合。它的synchronizedMap()
方法提供線程安全功能。
顧名思義, synchronizedMap()
返回一個同步的Map
背靠的Map
,我們在參數提供。為了提供線程安全, synchronizedMap()
允許通過返回的Map
進行對備用Map
所有訪問。
ConcurrentHashMap
在JDK 1.5中引入,是對HashMap
**的增強,它支持檢索和更新的高並發性**。 HashMap
不是線程安全的,因此在線程爭用期間可能會導致錯誤的結果。
ConcurrentHashMap
類是線程安全的。因此,多個線程可以在單個對像上運行而不會帶來複雜性。
在ConcurrentHashMap,
讀取操作是非阻塞的,而寫入操作則鎖定特定的段或存儲段。默認存儲桶或併發級別是16,這意味著在鎖定段或存儲桶後,任何時刻都可以寫入16個線程。
2.1。 ConcurrentModificationException
對於像HashMap
這樣的對象,不允許執行並發操作。因此,如果我們嘗試在迭代HashMap
同時對其進行更新,則將收到ConcurrentModificationException
。使用synchronizedMap()
時也會發生這種情況:
@Test(expected = ConcurrentModificationException.class)
public void whenRemoveAndAddOnHashMap_thenConcurrentModificationError() {
Map<Integer, String> map = new HashMap<>();
map.put(1, "baeldung");
map.put(2, "HashMap");
Map<Integer, String> synchronizedMap = Collections.synchronizedMap(map);
Iterator<Entry<Integer, String>> iterator = synchronizedMap.entrySet().iterator();
while (iterator.hasNext()) {
synchronizedMap.put(3, "Modification");
iterator.next();
}
}
但是, ConcurrentHashMap
並非如此:
Map<Integer, String> map = new ConcurrentHashMap<>();
map.put(1, "baeldung");
map.put(2, "HashMap");
Iterator<Entry<Integer, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
synchronizedMap.put(3, "Modification");
iterator.next()
}
Assert.assertEquals(3, map.size());
2.2。 null
支持
Collections.synchronizedMap()
和ConcurrentHashMap
不同的方式處理null
鍵和值。
ConcurrentHashMap
不允許在鍵或值中使用null
:
@Test(expected = NullPointerException.class)
public void allowNullKey_In_ConcurrentHasMap() {
Map<String, Integer> map = new ConcurrentHashMap<>();
map.put(null, 1);
}
但是,使用Collections.synchronizedMap()
,是否支持null
取決於輸入Map
.
當HashMap
或LinkedHashMap,
支持Collections.synchronizedMap()
時,我們可以使用一個null
作為鍵,並且可以使用任意數量的null
值LinkedHashMap,
而如果使用TreeMap
,則可以使用null
值,但不能使用null
鍵。
斷言我們可以對HashMap
支持的Collections.synchronizedMap()
使用null
鍵:
Map<String, Integer> map = Collections
.synchronizedMap(new HashMap<String, Integer>());
map.put(null, 1);
Assert.assertTrue(map.get(null).equals(1));
同樣,我們可以驗證Collections.synchronizedMap()
和ConcurrentHashMap
值中的null
支持。
3.性能比較
讓我們比較ConcurrentHashMap
和Collections.synchronizedMap().
的性能Collections.synchronizedMap().
在這種情況下,我們使用開源框架Java Microbenchmark Harness(JMH)來比較方法的性能(以納秒為單位) 。
我們對這些地圖上的隨機讀寫操作進行了比較。讓我們快速看一下我們的JMH基準代碼:
@Benchmark
public void randomReadAndWriteSynchronizedMap() {
Map<String, Integer> map = Collections.synchronizedMap(new HashMap<String, Integer>());
performReadAndWriteTest(map);
}
@Benchmark
public void randomReadAndWriteConcurrentHashMap() {
Map<String, Integer> map = new ConcurrentHashMap<>();
performReadAndWriteTest(map);
}
private void performReadAndWriteTest(final Map<String, Integer> map) {
for (int i = 0; i < TEST_NO_ITEMS; i++) {
Integer randNumber = (int) Math.ceil(Math.random() * TEST_NO_ITEMS);
map.get(String.valueOf(randNumber));
map.put(String.valueOf(randNumber), randNumber);
}
}
我們使用5個迭代和10個線程處理1,000個項目來運行性能基準。讓我們看一下基準測試結果:
Benchmark Mode Cnt Score Error Units
MapPerformanceComparison.randomReadAndWriteConcurrentHashMap avgt 100 3061555.822 ± 84058.268 ns/op
MapPerformanceComparison.randomReadAndWriteSynchronizedMap avgt 100 3234465.857 ± 60884.889 ns/op
MapPerformanceComparison.randomReadConcurrentHashMap avgt 100 2728614.243 ± 148477.676 ns/op
MapPerformanceComparison.randomReadSynchronizedMap avgt 100 3471147.160 ± 174361.431 ns/op
MapPerformanceComparison.randomWriteConcurrentHashMap avgt 100 3081447.009 ± 69533.465 ns/op
MapPerformanceComparison.randomWriteSynchronizedMap avgt 100 3385768.422 ± 141412.744 ns/op
以上結果表明**ConcurrentHashMap
性能優於****Collections.synchronizedMap()**
。
4.何時使用
當數據一致性至關重要時,我們應該偏愛Collections.synchronizedMap()
;對於寫操作比讀操作多的關鍵性能應用程序,我們應該選擇ConcurrentHashMap
。
5.結論
在本文中,我們演示了ConcurrentHashMap
和Collections.synchronizedMap()
之間的區別。我們還使用簡單的JMH基準測試展示了兩者的性能。