ConcurrentHashMap通过分段锁或CAS提升并发性能,支持高效读写与原子操作。1.7用Segment分段,1.8改用Node数组+CAS+synchronized;读不加锁,写只锁桶头;迭代器弱一致,不抛ConcurrentModificationException。初始化简单:new ConcurrentHashMap(); 推荐使用putIfAbsent、computeIfAbsent、merge等原子方法避免组合操作的线程安全问题,如计数可用merge(key, 1L, Long::sum)。注意设置初始容量减少扩容开销,避免在compute中执行耗时操作,遍历允许并发修改但不保证强一致性。

在高并发场景下,ConcurrentHashMap 是 Java 中最常用的线程安全 Map 实现。相比 HashMap(非线程安全)和 Hashtable 或 Collections.synchronizedMap()(全表锁),ConcurrentHashMap 通过分段锁机制或 CAS 操作实现了更高的并发读写性能。
1. ConcurrentHashMap 的核心优势
ConcurrentHashMap 在不同 JDK 版本中实现方式略有不同:
- JDK 1.7 使用 Segment 分段锁,将数据分成多个段,每个段独立加锁,提升并发度。
- JDK 1.8 改为基于 Node 数组 + 链表/红黑树,结合 CAS + synchronized 对链表头节点加锁,进一步提升性能。
主要优势包括:
- 支持多线程同时读取,无需加锁。
- 写操作只锁定局部结构(如桶的头节点),不阻塞整个 map。
- 迭代器弱一致性,不会抛出 ConcurrentModificationException。
2. 基本使用方法
声明和初始化非常简单:
立即学习“Java免费学习笔记(深入)”;
ConcurrentHashMap// 写操作
map.put("key1", 100);
map.put("key2", 200);
// 读操作
Integer value = map.get("key1");
// 安全地更新(推荐使用原子方法)
map.putIfAbsent("key3", 300); // 如果不存在才插入
map.replace("key1", 100, 150); // CAS 更新
3. 高并发下的安全操作建议
避免在并发环境中使用非原子组合操作。例如以下代码是**不安全的**:
由于我高估了大家对zblog程序的熟知度,发现还有很多站长并不是太熟悉这款程序,甚至连后台的登陆入口都不清楚。所以我晚上抽了一点点时间把该ZBLOG企业网站源码进行的修正,补充了大家的一些问题。并且我写了比较详细的使用教程,能够帮助新手朋友修改变成自己的企业网站使用。 修订版本改进了几处问题: 第一,修正了单页面中的顶部BANNER FLASH幻灯图片的显示错误问题; 第二,修正了在产品中心标题显
if (!map.containsKey("key")) {
map.put("key", value);
}
应替换为原子方法:
// ✅ 正确做法map.putIfAbsent("key", value);
其他常用原子方法:
-
computeIfAbsent(key, func):若 key 不存在,则计算并放入值(常用于缓存加载)。 -
computeIfPresent(key, func):若 key 存在,则重新计算值。 -
merge(key, value, function):合并已有值与新值(适合计数、累加等场景)。
示例:线程安全的计数器
ConcurrentHashMap// 多线程环境下安全累加
counter.merge("pageView", 1L, Long::sum);
4. 性能优化与注意事项
虽然 ConcurrentHashMap 已经很高效,但仍需注意以下几点:
- 合理设置初始容量和加载因子,减少扩容开销:
new ConcurrentHashMap(16, 0.75f, 4);
第三个参数是并发级别(JDK 1.8 后仅供参考)。 - 避免长时间持有大对象或执行耗时函数在 compute 方法中,防止阻塞其他线程。
- 遍历时使用 entrySet()、keySet() 等,允许并发修改,但不能保证实时一致性。
- 如需强一致性视图,需额外同步控制,ConcurrentHashMap 本身提供的是弱一致性读。
基本上就这些。只要善用 putIfAbsent、compute、merge 等原子方法,就能在高并发下安全高效地使用 ConcurrentHashMap。









