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基准测试展示了两者的性能。
0 评论