优先选用 concurrenthashmap,它通过分段锁(jdk 7)或 cas + synchronized 细粒度加锁(jdk 8+)实现高性能并发安全;其次可选 collections.synchronizedmap(全表锁,适合低并发)或不可变 map(如 map.of(),适用于只读场景)。

Java 中 HashMap 本身不提供任何并发控制,多线程同时 put 或 get 可能导致数据丢失、size() 错误、数组越界,甚至 JDK 7 下的死循环(扩容时链表成环)。解决的核心思路是:**避免共享可变状态,或用线程安全的替代品代替裸 HashMap**。
优先选 ConcurrentHashMap
这是最常用、最推荐的方案。它不是靠全局锁,而是采用分段锁(JDK 7)或 CAS + synchronized 细粒度加锁(JDK 8+),读操作无锁、写操作只锁对应桶,吞吐量远高于全表同步方案。
- 直接替换:把
new HashMap()换成new ConcurrentHashMap() - 复合操作更安全:用
putIfAbsent、computeIfAbsent、merge等原子方法,避免先查后 put 的竞态 - 遍历无需手动同步:它的迭代器是弱一致性(不会抛
ConcurrentModificationException),适合监控、日志等场景
低并发且简单场景可用 Collections.synchronizedMap
它对原始 HashMap 做一层包装,所有 public 方法都加了同一把对象锁(synchronized(mutex)),本质是全表串行化。
- 适合读多写少、并发量小、逻辑简单的情况,比如配置缓存初始化后只读不写
- 注意:遍历时必须显式同步整个 map,否则仍可能出错
- 示例:
synchronized(syncMap) { for (var e : syncMap.entrySet()) { ... } }
明确只读就用不可变 Map
如果 map 构建完成后不再修改,从根源上杜绝并发问题,性能和安全性都最高。
- JDK 9+ 推荐
Map.of()或Map.copyOf(),轻量、不可变、线程安全 - 需要动态构建或更多功能,可用 Guava 的
ImmutableMap.builder() - 注意:不可变 map 不支持
put、clear等修改操作,调用会抛UnsupportedOperationException
其他方案不建议新项目使用
Hashtable 虽然线程安全,但所有方法都用 synchronized 修饰,是粗粒度全表锁,高并发下性能差,且已属遗留类;手写 synchronized 块或 ReentrantLock 包裹 HashMap 容易遗漏边界(如遍历、复合操作),维护成本高,没必要重复造轮子。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











