8.Collections.synchronizedMap 与 ConcurrentMap 的区别与适用场景

Collections.synchronizedMap 与 ConcurrentMap 的区别与适用场景

🚀 高频指数:★★★★☆
🎯 你将收获:Java中两种线程安全Map的核心原理、性能差异、使用场景与底层机制。


一、问题导入

💬 面试官:

  1. 你知道 Collections.synchronizedMap()ConcurrentHashMap 的区别吗?
  2. 什么时候该用前者,什么时候该用后者?

很多开发者知道“一个用同步块,一个高并发”,但不清楚它们的本质差异。
这题表面是集合问题,实际上考察的是:锁粒度 + 并发机制 + 线程安全保证层级


二、两者的基本定义

类型来自包出现版本线程安全机制
Collections.synchronizedMap()java.utilJDK 1.2外层整体加锁(synchronized)
ConcurrentHashMapjava.util.concurrentJDK 1.5分桶锁 + CAS + 局部 synchronized

☕️ 口诀:“一个外包锁,一个分区锁。”


三、Collections.synchronizedMap 原理

Collections.synchronizedMap() 是通过装饰器模式包装普通的 Map
在所有访问操作上加 synchronized,保证原子性。

核心实现:

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
    return new SynchronizedMap<>(m);
}

static class SynchronizedMap<K,V> implements Map<K,V>, Serializable {
    private final Map<K,V> m;
    final Object mutex; // 共享锁对象

    public V get(Object key) {
        synchronized (mutex) { return m.get(key); }
    }

    public V put(K key, V value) {
        synchronized (mutex) { return m.put(key, value); }
    }
}

特点:

  • 每次访问(get、put、remove)都加全局锁;
  • 同一时间仅允许一个线程访问 Map;
  • 线程安全但并发性能差
  • 迭代时需手动加锁,否则可能抛出异常。
Map<String,String> map = Collections.synchronizedMap(new HashMap<>());
synchronized (map) {
    for (String key : map.keySet()) { ... }
}

四、ConcurrentHashMap 原理

ConcurrentHashMap 内部通过 分段锁 + CAS + 局部 synchronized 实现高并发访问。

特点:

  • 读操作无锁;
  • 写操作仅锁定单个桶(Node链表或树);
  • 多线程同时写入不同桶互不影响;
  • 支持弱一致性遍历(不会抛异常)。

✅ 相比 synchronizedMapConcurrentHashMap 性能更高,可并发写入。


五、并发特性对比

对比项Collections.synchronizedMapConcurrentHashMap
线程安全
锁粒度整个Map(全局锁)桶级锁(局部锁)
读操作加锁无锁
写操作加锁CAS + synchronized
并发度1(单线程访问)多线程(默认支持16+并发)
迭代时修改抛 ConcurrentModificationException弱一致性,安全
是否允许 null 键/值
性能表现低并发时可接受高并发性能优越

☕️ 口诀:“同步Map一锁到底,并发Map桶桶分离。”


六、源码差异(简化版)

synchronizedMap:

public V put(K key, V value) {
    synchronized (mutex) {
        return m.put(key, value);
    }
}

ConcurrentHashMap:

final V putVal(K key, V value, boolean onlyIfAbsent) {
    for (;;) {
        if (casTabAt(tab, i, null, new Node<>(hash, key, value, null)))
            break; // 无锁插入成功
        else synchronized (f) {
            // 局部锁写入
        }
    }
}

七、性能表现(结论)

并发场景建议选择原因
低并发,线程少✅ synchronizedMap简单稳定
高频读写并发✅ ConcurrentHashMap性能高
多线程缓存✅ ConcurrentHashMap支持CAS与分段扩容
迭代读取✅ ConcurrentHashMap支持弱一致性

⚙️ 实际工程中,ConcurrentHashMap 已几乎完全取代 synchronizedMap


八、项目实战建议

  • 缓存在线用户表任务状态表:使用 ConcurrentHashMap
  • 同步块简化低并发配置类 Map:可用 synchronizedMap
  • 迭代同步时,Collections.synchronizedMap 需外层 synchronized (map)
  • 不要在高并发环境下使用 synchronizedMap 做计数器或任务队列。

九、面试官追问清单

面试问题答题要点
线程安全 Map 有哪些?Hashtable、synchronizedMap、ConcurrentHashMap
Hashtable 和 synchronizedMap 区别?Hashtable 内部方法自带 synchronized,前者是装饰器包装。
为什么 ConcurrentHashMap 性能高?分桶锁 + CAS 并发写入,无全局锁。
get 操作是否加锁?synchronizedMap 会加锁;ConcurrentHashMap 不加锁。
允许 null 吗?synchronizedMap 允许,ConcurrentHashMap 不允许。

十、口诀记忆

☕️ “同步一锁全,分桶并发高;读锁卡顿多,CAS 提速跑。”


十一、小结

知识点关键结论
synchronizedMap全局锁,简单但性能差
ConcurrentHashMap分桶锁 + CAS,读写并行
适用场景前者低并发,后者高并发
锁粒度整体 vs 局部
是否推荐新项目中推荐 ConcurrentHashMap

✅ 一句话总结:“synchronizedMap 是老派同步,ConcurrentHashMap 是现代并发。”


🔗 延伸阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愤怒的代码

如果您有受益,欢迎打赏博主😊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值