Map.merge() 是 Java 8 提供的线程安全统计更新方法,通过“查-算-存”原子操作避免并发计数丢失;ConcurrentHashMap 中基于 CAS 或锁实现 UPSERT,支持灵活合并逻辑如累加、取最大值等,但要求 key/value 非 null。

Map.merge() 是 Java 8 引入的“一行解决统计更新”的核心方法,它天然支持键存在与否的统一处理,同时在 ConcurrentHashMap 中保证原子性,避免多线程下计数丢失。
为什么 merge 比传统写法更可靠?
传统统计常写成:
- 先 get(key),判断是否为 null
- 再 put(key, old == null ? 1 : old + 1)
- 但 get + put 非原子操作,在并发场景下可能被其他线程覆盖,导致计数少加
merge 则把“查-算-存”封装为单次调用,ConcurrentHashMap 的 merge 实现底层基于 CAS 或锁机制,真正实现线程安全的 UPSERT(插入或更新)。
统计计数的典型写法
以单词频次统计为例:
- countMap.merge("apple", 1, Integer::sum):key 不存在 → 直接存 1;存在 → 执行 旧值 + 1
- 等价于 (old, _new) -> old == null ? _new : old + _new,但无需手动判空
- Integer::sum 是最简合并函数,语义清晰,性能高效
合并函数的灵活控制
remappingFunction 不仅限于累加,还能按需定制逻辑:
- 保留最大值:(old, newVal) -> Math.max(old, newVal)
- 只保留首次值(不覆盖):(old, newVal) -> old
- 拼接字符串:(old, newVal) -> old == null ? newVal : old + "," + newVal
- 清空该键:(old, newVal) -> null(触发 remove)
注意 null 值与线程安全边界
merge 行为依赖 Map 实现:
- HashMap 不是线程安全的,merge 只是逻辑简洁,不保证并发安全
- ConcurrentHashMap 支持线程安全的 merge,但不允许 key 或 value 为 null(否则抛 NullPointerException)
- 若业务允许 null 值,建议用 compute() 替代,或提前过滤

















