拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Collections.synchronizedMap与ConcurrentHashMap

Collections.synchronizedMap与ConcurrentHashMap

白鹭 - 2021-11-24 420 0 0

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 .HashMapLinkedHashMap,支持Collections.synchronizedMap()时,我们可以使用一个null作为键,并且可以使用任意数量的nullLinkedHashMap,而如果使用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.性能比较

让我们比较ConcurrentHashMapCollections.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.结论

在本文中,我们演示了ConcurrentHashMapCollections.synchronizedMap()之间的区别。我们还使用简单的JMH基准测试展示了两者的性能。

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *