concurrenthashmap 是 java 高并发线程安全 map,采用 cas + synchronized 锁单个 node 实现高效并发;需合理设 initialcapacity(如 2048),保持 loadfactor 默认 0.75,concurrencylevel 在 jdk 8+ 仅作参考;优先用 putifabsent、computeifabsent、merge 等原子方法;禁止 key/value 为 null,size() 返回近似值,应改用 mappingcount();迭代器弱一致;避免在 compute* 中执行 i/o;无需额外 synchronized,也不适用于配置中心场景。

ConcurrentHashMap 是 Java 中专为高并发场景设计的线程安全 Map,它不靠全局锁,而是通过细粒度控制(JDK 8+ 是 CAS + synchronized 锁单个 Node)让读写尽可能并行,既安全又高效。关键不是“能不能用”,而是“怎么用对”。
选对初始化参数,避免早期扩容拖慢性能
初始容量(initialCapacity)应按预估最大元素数设置,比如预计存 2000 条,可设为 2048(自动取最近 2 的幂)。这样能减少 rehash 次数;负载因子(loadFactor)保持默认 0.75 即可,一般无需调整;concurrencyLevel 在 JDK 8+ 仅作内部并行度参考,传 4、8 或 16 都不影响实际并发能力,不必刻意调大。
优先使用原子方法,别自己拼 get + put
手动判断再插入容易引发竞态条件,例如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
❌ 错误写法:
if (!map.containsKey(k)) map.put(k, v);—— 中间可能被其他线程抢先插入 -
✅ 正确写法:
map.putIfAbsent(k, v)(键不存在才设值) -
✅ 更适合缓存场景:
map.computeIfAbsent(k, key -> loadExpensiveValue())—— 多线程下只执行一次加载逻辑 -
✅ 计数器推荐:
map.merge("count", 1L, Long::sum)或map.compute("count", (k, v) -> v == null ? 1L : v + 1)
避开几个典型陷阱
ConcurrentHashMap 虽然线程安全,但不是“万能锁替代品”:
- key 和 value 都不能为 null —— 否则抛 NullPointerException,这是设计使然,用于区分“不存在”和“值为空”
-
size() 返回的是近似值 —— 高并发下遍历所有段求和开销大且结果可能过期;需要精确计数请用
mappingCount()(返回 long,无锁、更准) - 迭代器是弱一致的 —— 不抛 ConcurrentModificationException,但遍历时看到的可能是某个时间点的快照,新增或删除的元素不一定立即可见
- 不要在 compute* 方法里做 I/O 或睡眠 —— 会阻塞整个桶的写操作,影响其他 key 的并发更新
不需要额外同步,也别把它当配置中心
ConcurrentHashMap 本身已保证所有单操作原子性,切勿再用 synchronized 包裹它的方法调用,否则等于废掉其并发优势。同时,它不提供版本管理、变更监听或批量原子更新能力——如果业务需要这些,应选用 Curator + ZooKeeper 或 Etcd 等外部协调服务,而不是强行扩展 ConcurrentHashMap。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










