外观
HashMap线程安全吗,如何保证线程安全,使用什么集合
⭐ 题目日期:
美团 - 2025/4/4
📝 题解:
HashMap 在 Java 中不是线程安全的。在多线程环境下,如果多个线程同时对 HashMap 进行修改(如添加、删除或扩容操作),可能会导致数据不一致、死循环或其他未定义行为。以下是保证线程安全的常用方法及对应的集合类:
一、如何保证线程安全?
1. 使用 Collections.synchronizedMap
Map<K, V> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
- 原理:通过给所有方法添加
synchronized
关键字,锁住整个 Map 实例。 - 缺点:锁粒度粗,高并发时性能较差。
2. 使用 ConcurrentHashMap
Map<K, V> concurrentMap = new ConcurrentHashMap<>();
- 原理:
- Java 7:分段锁(Segment),将数据分成多个段,每段独立加锁,提高并发度。
- Java 8+:改用
CAS
(Compare-And-Swap)和synchronized
锁单个桶(Node),进一步优化并发性能。
- 优点:高并发场景下性能优异,推荐使用。
3. 使用 Hashtable
(不推荐)
Map<K, V> hashtable = new Hashtable<>();
- 原理:所有方法通过
synchronized
加锁,锁住整个实例。 - 缺点:性能差,已逐渐被
ConcurrentHashMap
取代。
二、如何选择线程安全集合?
集合类 | 适用场景 | 性能 | 推荐度 |
---|---|---|---|
ConcurrentHashMap | 高并发读写、大规模数据 | 高 | ★★★★★ |
Collections.synchronizedMap | 低并发、简单同步需求 | 中低 | ★★☆ |
Hashtable | 遗留代码兼容(不推荐新项目使用) | 低 | ★☆☆ |
三、关键区别总结
- 锁粒度:
Hashtable
和synchronizedMap
锁整个实例。ConcurrentHashMap
锁单个桶(Java 8+)或分段(Java 7),锁粒度更细。
- 性能:
ConcurrentHashMap
>synchronizedMap
>Hashtable
。
- 适用场景:
- 优先选择
ConcurrentHashMap
,几乎覆盖所有需要线程安全 Map 的场景。
- 优先选择
四、其他线程安全集合
CopyOnWriteArrayList
:读多写少的线程安全 List。ConcurrentLinkedQueue
:高并发队列。BlockingQueue
实现类:如LinkedBlockingQueue
,用于生产者-消费者模型。
总结:在多线程环境中,优先使用 ConcurrentHashMap
,避免使用 Hashtable
和手动同步的 synchronizedMap
。