ConcurrentHashMap:高性能并发 Map
ConcurrentHashMap 是什么
ConcurrentHashMap 是 HashMap 的并发版本,提供高并发下的线程安全。
java
// HashMap:非线程安全
Map<String, Integer> hash = new HashMap<>();
// ConcurrentHashMap:高并发线程安全
ConcurrentHashMap<String, Integer> chm = new ConcurrentHashMap<>();vs HashMap / synchronizedMap
| 特性 | HashMap | synchronizedMap | ConcurrentHashMap |
|---|---|---|---|
| 线程安全 | ❌ | ✅(全局锁) | ✅(分段锁/CAS) |
| 并发读 | — | 阻塞 | 无锁读 |
| 性能 | 最快 | 慢 | 较快 |
| 迭代安全 | Fail-Fast | 需额外同步 | Fail-Safe |
JDK 8+ 的 CAS + synchronized
JDK 8 废弃了 JDK 7 的 Segment 分段锁,改为 CAS + synchronized:
java
// 简单操作用 CAS(无锁操作)
U.compareAndSwapObject(table, ...);
// 需要锁定时用 synchronized(只锁单个桶)
synchronized (node) {
// 对单个桶操作
}每个桶一把锁,减少了锁竞争。
红黑树优化
当单个桶内链表过长时,转为红黑树:
java
// 链表长度 >= 8 且 数组容量 >= 64 → 转红黑树
// 和 HashMap 一样核心 API
基本操作
java
ConcurrentHashMap<String, Integer> chm = new ConcurrentHashMap<>();
// put / get
chm.put("apple", 3);
chm.get("apple"); // 3
// putIfAbsent:不存在才插入
chm.putIfAbsent("apple", 10); // 返回 3(旧值),不覆盖
chm.putIfAbsent("banana", 5); // 返回 null,插入成功原子操作
java
chm.put("count", 0);
// compute:重新计算值
chm.compute("count", (k, v) -> v == null ? 1 : v + 1);
// merge:合并
chm.merge("count", 1, Integer::sum);
// computeIfAbsent:不存在才计算
chm.computeIfAbsent("newKey", k -> calculateValue(k));批量操作
java
// forEach:遍历(Fail-Safe,不会抛 ConcurrentModificationException)
chm.forEach((k, v) -> System.out.println(k + " = " + v));
// search:搜索
String found = chm.search(1, (k, v) -> v > 10 ? k : null);
// reduce:聚合
Long sum = chm.reduceValues(1, Long::sum);与 synchronizedMap 的性能对比
java
// 10 个线程并发写入 10 万元素
// synchronizedMap: ~8000 ms
// ConcurrentHashMap: ~200 ms
// 快了 40 倍!迭代安全性
ConcurrentHashMap 的迭代器是 Fail-Safe 的,遍历的是快照副本:
java
ConcurrentHashMap<String, Integer> chm = new ConcurrentHashMap<>();
chm.put("a", 1);
chm.put("b", 2);
// 遍历过程中可以并发修改
for (Map.Entry<String, Integer> e : chm.entrySet()) {
System.out.println(e.getKey() + " = " + e.getValue());
chm.put("c", 3); // 不抛异常
}synchronizedMap 做不到这一点。
注意事项
不允许 null
java
ConcurrentHashMap<String, Integer> chm = new ConcurrentHashMap<>();
// ❌ 不允许 null key 或 null value
chm.put(null, 1); // NullPointerException
chm.put("a", null); // NullPointerException不适合做缓存
ConcurrentHashMap 不会自动清理:
java
// ❌ ConcurrentHashMap 不支持弱引用或自动过期
// 适合做计数器、共享状态等,不适合做大缓存
// ✅ 缓存用 Cache 或 WeakHashMap
LoadingCache<Key, Value> cache = Caffeine.newBuilder().build();总结
| 要点 | 说明 |
|---|---|
| 线程安全 | CAS + synchronized |
| 性能 | 比 synchronizedMap 快 10-40 倍 |
| 迭代安全 | Fail-Safe,遍历时无需额外同步 |
| null | 不允许 null key/value |
| 适用 | 高并发 Map、计数器、共享状态 |
一句话:ConcurrentHashMap 是「高并发场景下的 HashMap」——用分段锁/CAS 替代全局锁,让多个线程并发读写而不阻塞。
