Java ConcurrentHashMap 和 SynchronizedMap 的区别

Java ConcurrentHashMap 和 SynchronizedMap 的区别

  • java.util.concurrent.ConcurrentHashMap 和 java.util.Collections$SynchronizedMap 两者都是 Java 中线程安全的 Map 实现

ConcurrentHashMap

  • ConcurrentHashMap 是专门为并发环境设计的,性能优势显著,尤其在读多写少或高并发写场景,适用于绝大多数高并发场景(比如缓存、实时计数器和高频数据统计等)
  • ConcurrentHashMap 的 key 和 value 均不允许为 null
  • 提供 putIfAbsent、computeIfAbsent 和 replace 等原子方法,避免手动同步的复杂性

Collections$SynchronizedMap

  • SynchronizedMap 通过包装一个普通的 Map(比如 HashMap)并对其操作进行同步的方式来实现的,大部分的读写操作都用 synchronized 关键字(对象锁)来保证线程安全,而迭代方法没有加锁,所以在使用迭代方法的时候必须要手动处理线程同步问题(避免抛出异常),由于读写操作都需要竞争同一把锁,所以高并发下性能显著下降
  • 常用方法 Collections.synchronizedMap 返回一个 SynchronizedMap 对象
  • SynchronizedMap 比较适合需要简单地将普通非线程安全的 Map 转换为线程安全的 Map 的情况,适用于旧代码兼容场景,需避免在高并发环境中使用
  • 复合操作需要额外同步逻辑
java 复制代码
Map<String, Integer> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
//需要手动加锁才能保证原子性
synchronized (synchronizedMap) { 
    if (!synchronizedMap.containsKey(key)) {
        synchronizedMap.put(key, value);
    }
}
java 复制代码
Map<String, Integer> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
//迭代时必须处理同步
synchronized (synchronizedMap) { 
    for (Map.Entry<String, Integer> entry : synchronizedMap.entrySet()) {
        System.out.println(entry.getKey() + ": " + entry.getValue());
    }
}

总结

  • 迭代器:ConcurrentHashMap 是弱一致性的,迭代过程中允许其他线程修改 Map,不会抛出异常,但迭代器可能不会反映最新的修改(仅保证迭代时的数据是线程安全的),而 SynchronizedMap 在迭代过程中如果被其他线程修改时(比如 put 或 remove),会立即抛出异常
  • 空值处理:ConcurrentHashMap 禁止 null 键或值(避免歧义,为了避免出现 get 方法返回 null 无法区分是 key 不存在还是 value 为 null 的情况),而 SynchronizedMap 允许 null 键和值(沿用底层 Map 特性)
  • 锁机制:ConcurrentHashMap 只对需要修改的部分进行加锁,而不是整个 Map,而 SynchronizedMap 使用 synchronized 关键字对整个 Map 对象加锁,读写操作都需要获取全局锁,性能较低
  • 适用场景:ConcurrentHashMap 适用于高并发、高性能要求场景,特别是读多写少的情况,而 SynchronizedMap 则适用于并发程度较低且对性能要求不高的场景,实现简单,兼容性好,如果需要支持 null 键或值,可以选用 SynchronizedMap,如果需要保证迭代操作的强一致性,可以考虑使用 SynchronizedMap 并手动加锁
相关推荐
鬼手点金1 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github
paopaokaka_luck2 小时前
滑雪场管理系统(AI智能助手流式对话,ECharts 运营数据分析、教练、雪具与场地一体化预约,钱包支付退款、订单核销与服务评价)
java·人工智能·spring boot·网络协议·数据分析·echarts
Wang's Blog2 小时前
Java 项目实战: 交友项目 - Dubbo 的内部结构与一次调用的完整链路
java·dubbo
Wang's Blog2 小时前
Java 项目实战: 交友项目 - Dubbo 入门引导
java·dubbo·交友
蜗牛互联网3 小时前
Python Agent工具调用的白名单、参数校验与审批门禁
java·服务器·前端·人工智能·后端·python
SL_staff3 小时前
当规则引擎开始‘懂业务’:JVS-Rules金融风控四大原生能力拆解
java·python·全栈
Shaoshing3 小时前
前缀和与差分
java·数据结构·算法·前缀和·差分
dd聊技术4 小时前
Prompt 从代码常量搬进数据库:改一句话,不用再发一次版
java·后端
ly76894 小时前
Spring Data MongoDB 批量写入实践:BulkOperations 批大小与写关注权衡
java·mongodb·spring·批量写入·bulkoperations·写关注·mongotemplate
TAKETODAY4 小时前
Netty 是怎么把 HTTP 请求交给 MVC 的?一个请求的完整链路
java·netty