行业资讯 2025年08月6日
0 收藏 0 点赞 848 浏览 3706 个字
摘要 :

文章目录 1.Java ConcurrentMap是如何工作的? 2.ConcurrentMap实现 2.1. ConcurrentHashMap 2.2. ConcurrentSkipListMap 3.ConcurrentMap操作 3.1. 创建ConcurrentM……




  • 1.Java ConcurrentMap是如何工作的?
  • 2.ConcurrentMap实现
    • 2.1. ConcurrentHashMap
    • 2.2. ConcurrentSkipListMap
  • 3.ConcurrentMap操作
    • 3.1. 创建ConcurrentMap
    • 3.2. 添加条目
    • 3.3. 删除条目
    • 3.4. 遍历条目
    • 3.5. 将HashMap转换为ConcurrentMap
  • 4.处理ConcurrentMap中的缺失键
  • 5.结论

在本教程中,我们将详细了解Java集合框架中的ConcurrentMap接口以及ConcurrentMap与HashMap之间的区别。ConcurrentMap用于在Java中创建线程安全的Map,以同步方式存储对象作为键值对。

尽管在Java中已经有HashMap和HashTable,但在并发上下文中,它们都不适用得很好。因此,在线程安全的应用程序中推荐使用并发映射。

1.Java ConcurrentMap是如何工作的?

在内部,ConcurrentMap使用数据段(片段或分区)将Map分为一定数量的分区(默认为16)。当线程执行添加或更新操作时,ConcurrentMap锁定要进行更新的特定分区。但它允许其他线程从其他未锁定的分区读取任何值。

这意味着在多线程应用程序中访问ConcurrentMap时,我们不需要使用同步块,因为数据一致性在内部得到维护。在正常应用程序中,单个分区存储合理数量的键值对,并允许多个线程执行读操作。并且读取性能也非常理想。当碰撞太多时,表会动态扩展。

请注意,size()、isEmpty()和containsValue()方法的结果反映了Map的瞬时状态,通常用于监控或估算,而不用于程序控制。

2.ConcurrentMap实现

以下类实现了Java中的ConcurrentMap。

2.1. ConcurrentHashMap

ConcurrentHashMap是ConcurrentMap的实现类,类似于HashTable,不同之处在于它将数据存储在小的内存段中,以便供并发线程独立访问。

默认情况下,它创建16个可以由并发线程访问并为修改记录而锁定的分段。它使用happens-before概念来更新记录。对于读取操作,它不执行任何锁定,并为线程提供最新的更新数据。

2.2. ConcurrentSkipListMap

它是ConcurrentMap和ConcurrentNavigableMap的实现类。它按照自然排序顺序或在初始化时由比较器指定的顺序存储数据。它的实现基于SkipLists数据结构,对于插入、删除和搜索操作具有整体O(log n)复杂度。

还要注意,ConcurrentHashMap中的键不是按排序顺序排列的,因此对于需要排序的情况,ConcurrentSkipListMap是更好的选择。它是TreeMap的并发版本,默认按升序对键进行排序。

3.ConcurrentMap操作

让我们学习如何在ConcurrentMap上执行各种操作。

3.1. 创建ConcurrentMap

要使用ConcurrentMap,我们可以创建其实现类的实例。我们可以调用构造函数并传递所需的参数,如初始容量、负载因子和并发级别。

  • 默认构造函数将创建一个初始容量为16和负载因子为0.75f的空ConcurrentMap。
  • 负载因子控制Map内部的密集打包,进一步优化内存使用。
  • 并发级别控制Map中分区的数量。例如,将并发级别设置为1将确保只创建和维护一个分区。

请注意,这些参数只影响Map的初始大小,可能在Map调整大小时不会考虑。

ConcurrentMap<Integer, String> cmap = new ConcurrentHashMap<>();
ConcurrentHashMap(int initialCapacity);
ConcurrentHashMap(int initialCapacity, float loadFactor);
ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel);

通过将现有Map传递给其构造函数,可以初始化具有与给定Map相同条目的ConcurrentMap。

ConcurrentHashMap(Map<? extends K,? extends V> m)

3.2. 添加条目

要向ConcurrentMap中添加元素,我们可以使用以下其中一种方法:

  • put(key, value):接受两个参数,第一个参数是键,第二个是值。键和值都不能为null。
  • putIfAbsent(key, value):如果指定键尚未与值关联(或映射到null),则将其与给定值关联并返回null,否则返回当前值。
  • computeIfAbsent(key, mappingFunction):如果指定键尚未与值关联,它尝试使用给定的映射函数计算值,并将其输入Map,除非为null。当计算值是昂贵的操作(例如从远程系统或数据库获取值)时,此方法非常有用。此方法确保仅在Map上不存在值时才会发生计算,从而防止不必要的计算。

对于compute…和merge…操作,如果计算值为null,则如果存在则删除键值映射,或者如果之前不存在则保持不变。

ConcurrentMap<Integer, String> cmap = new ConcurrentHashMap<>();
cmap.put(1, \"Delhi\");
cmap.putIfAbsent(2, \"NewYork\");
cmap.computeIfAbsent(\"3\", k -> getValueFromDatabase(k));

3.3. 删除条目

使用remove()方法通过其键来删除条目。

cmap.remove(2);

3.4. 遍历条目

要遍历ConcurrentMap的键、值或条目,可以使用简单的for循环或增强的for循环。

ConcurrentMap<Integer, String> cmap = new ConcurrentHashMap<>();
cmap.put(1, \"Delhi\");
cmap.put(2, \"NewYork\");
cmap.put(3, \"London\");
// 迭代concurrent map keys
for (Integer entry : cmap.keySet()) {
  System.out.println(\"Entry -- \" + entry);
}
// 迭代concurrent map values
for (String value : cmap.values()) {
  System.out.println(\"Value -- \" + value);
}
// 迭代concurrent map entries
for (Map.Entry<Integer, String> entry : cmap.entrySet()) {
  System.out.println(entry.getKey() + \" -- \" + entry.getValue());
}

ConcurrentMap还支持流操作。在Stream中的批量操作中,与上述迭代器类似,它不会抛出ConcurrentModificationException。

Stream.of(cmap.entrySet()).forEach(System.out::println);

3.5. 将HashMap转换为ConcurrentMap

要将HashMap转换为ConcurrentMap,使用其构造函数并将hashmap作为构造函数参数。

Map<Integer, String> hashmap = ...;
ConcurrentMap<Integer, String> cmap = new ConcurrentHashMap<>(hashmap);

4.处理ConcurrentMap中的缺失键

Java在其1.8版本中添加了一个新方法getOrDefault()来处理缺失的键。如果指定键在ConcurrentMap中不存在,此方法将返回默认值。

ConcurrentMap<Integer, String> cmap = new ConcurrentHashMap<>();
cmap.put(1, \"Delhi\");
cmap.put(2, \"NewYork\");
cmap.put(3, \"London\");
String val = cmap.getOrDefault(1,\"Bombay\");
System.out.println(\"Value = \"+val);       //打印 Delhi
val = cmap.getOrDefault(10, \"Kolkata\");
System.out.println(\"Value = \"+val);       //打印 Kolkata

5.结论

ConcurrentMap及其实现适用于高度并发的应用程序。在本教程中,我们学习了在并发操作期间更改映射实例行为的初始构造函数参数。

我们还学习了如何执行映射的各种操作,使用示例以及实现最佳性能的最佳实践。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/9369.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号