应直接使用 concurrenthashmap 初始化,避免转换或包装 hashmap;其原子方法如 computeifabsent、replace、merge 可安全高效实现复合操作。

直接用 ConcurrentHashMap 替代是最安全、最推荐的方式,而不是“转换”原有 HashMap。所谓“转换”,本质是换掉底层实现,不是在原对象上加锁或包装——因为 HashMap 本身的设计不支持运行时线程安全升级。
优先用 ConcurrentHashMap 初始化
不要先创建普通 HashMap 再想办法“转”成线程安全的。从源头就用线程安全的实现:
- 新建映射直接用
new ConcurrentHashMap() - 如果已有数据,可传入初始化容量或使用构造函数批量导入:
new ConcurrentHashMap(existingMap)(注意:这是深拷贝键值对,不是包装) - 避免把
new HashMap()作为参数传给Collections.synchronizedMap()后长期复用——它只是加了一层同步壳,读写仍串行
慎用 Collections.synchronizedMap()
它把普通 Map 包装成同步版本,但所有 public 方法都用同一个锁(this 或指定 mutex)保护:
- 读操作也要排队,吞吐量低,适合低并发、简单场景
- 迭代时必须手动同步整个 map:
synchronized(syncMap) { syncMap.keySet().iterator()... },否则可能抛ConcurrentModificationException - 不适用于需要复合操作原子性的场景(如“检查后插入”),它只保证单个方法原子,不保证多步逻辑
彻底避开老式 Hashtable
虽然它是线程安全的,但已被淘汰:
- 每个方法都加
synchronized,锁粒度是整个表,比synchronizedMap还重 - 不支持
null键和null值,API 设计僵硬 - 没有现代并发优化(如 CAS、分段控制、红黑树),JDK 1.8+ 中性能远不如 ConcurrentHashMap
需要复合操作?用 ConcurrentHashMap 的原子方法
它提供了多个带条件的原子方法,比手动加锁更高效、更安全:
-
computeIfAbsent(key, mappingFunction):键不存在时才计算并放入,整个过程原子 -
replace(key, oldValue, newValue):仅当旧值匹配时才替换,避免 ABA 问题 -
merge(key, value, remappingFunction):存在则合并,不存在则插入,一步到位 - 这些方法内部由 CAS 和细粒度锁保障,无需额外同步
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











