面试题:简述ConcurrentHashMap 和 Hashtable 的区别 ?

ConcurrentHashMap 和 Hashtable 都是 Java 中线程安全的键值对集合,但它们在实现方式、性能和使用场景上有显著区别。以下是两者的主要区别:


1. 锁的粒度

  • Hashtable
    • 使用全局锁(synchronized 修饰方法),即对整个哈希表加锁。
    • 在多线程环境下,同一时间只能有一个线程操作 Hashtable,其他线程会被阻塞,导致性能较差。
  • ConcurrentHashMap
    • 使用分段锁(JDK 7)或 CAS + synchronized(JDK 8),锁的粒度更细。
    • 在 JDK 7 中,ConcurrentHashMap 将数据分成多个段(Segment),每个段独立加锁,不同段可以并发操作。
    • 在 JDK 8 中,ConcurrentHashMap 取消了分段锁,改为对每个桶(Node)使用 synchronized 或 CAS 操作,进一步提高了并发性能。

2. 并发性能

  • Hashtable
    • 由于使用全局锁,并发性能较差,尤其是在高并发场景下,线程竞争激烈,性能下降明显。
  • ConcurrentHashMap
    • 由于锁的粒度更细,允许多个线程同时读写不同的段或桶,并发性能显著优于 Hashtable
    • 在 JDK 8 中,ConcurrentHashMap 的并发性能进一步提升,接近无锁的性能。

3. 空值支持

  • Hashtable
    • 不允许键或值为 null,否则会抛出 NullPointerException
  • ConcurrentHashMap
    • 不允许键或值为 null,否则会抛出 NullPointerException
    • 这是因为在并发环境下,null 值的二义性(表示键不存在或值为 null)会导致歧义。

4. 迭代器的弱一致性

  • Hashtable
    • 迭代器是强一致性的,即在迭代过程中,其他线程不能修改 Hashtable,否则会抛出 ConcurrentModificationException
  • ConcurrentHashMap
    • 迭代器是弱一致性的,即在迭代过程中,其他线程可以修改 ConcurrentHashMap,迭代器不会抛出异常,但可能反映部分修改。

5. 实现复杂度

  • Hashtable
    • 实现简单,直接使用 synchronized 修饰方法。
  • ConcurrentHashMap
    • 实现复杂,JDK 7 使用分段锁,JDK 8 使用 CAS + synchronized,需要处理更多的并发问题。

6. 适用场景

  • Hashtable
    • 适用于低并发场景,或者需要强一致性的场景。
  • ConcurrentHashMap
    • 适用于高并发场景,性能要求较高的场景。

总结对比:

特性HashtableConcurrentHashMap
锁的粒度全局锁(整个表加锁)分段锁(JDK 7)或桶锁(JDK 8)
并发性能较差较好
空值支持不允许键或值为 null不允许键或值为 null
迭代器一致性强一致性弱一致性
实现复杂度简单复杂
适用场景低并发场景高并发场景

示例代码:

Hashtable

Hashtable<String, String> hashtable = new Hashtable<>();
hashtable.put("key1", "value1");
hashtable.put("key2", "value2");

// 多线程操作
new Thread(() -> {
    hashtable.put("key3", "value3");
}).start();

new Thread(() -> {
    System.out.println(hashtable.get("key1"));
}).start();

ConcurrentHashMap

ConcurrentHashMap<String, String> concurrentHashMap = new ConcurrentHashMap<>();
concurrentHashMap.put("key1", "value1");
concurrentHashMap.put("key2", "value2");

// 多线程操作
new Thread(() -> {
    concurrentHashMap.put("key3", "value3");
}).start();

new Thread(() -> {
    System.out.println(concurrentHashMap.get("key1"));
}).start();

总结:

  • Hashtable 是早期的线程安全集合,实现简单但性能较差。
  • ConcurrentHashMap 是现代化的高并发集合,通过细粒度锁或 CAS 机制提供了更好的并发性能。
  • 在高并发场景下,优先选择 ConcurrentHashMap
THE END
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容