MST

星途 面试题库

面试题:Java线程安全集合类在高并发场景下的应用及原理

在高并发场景下,`ConcurrentHashMap`和`HashTable`都能保证线程安全,阐述它们实现线程安全机制的差异,以及在不同读写比例场景下如何选择更合适的集合类。
45.5万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

线程安全机制差异

  1. HashTable
    • HashTable 是通过对几乎所有的操作(如 putget 等)都使用 synchronized 关键字进行同步,这意味着在同一时间只有一个线程能够访问 HashTable 的方法,从而保证线程安全。这种方式是对整个 HashTable 进行锁定,粒度较大,并发性能相对较差。
  2. ConcurrentHashMap
    • 在 JDK 1.7 中,ConcurrentHashMap 采用分段锁(Segment)的机制。它将整个哈希表分成多个段(Segment),每个段就像是一个小的 HashTable,每个段都有自己的锁。当一个线程访问某个段时,只会锁定这个段,而其他段仍然可以被其他线程访问,大大提高了并发性能。
    • 在 JDK 1.8 中,ConcurrentHashMap 摒弃了分段锁机制,采用了 CAS(Compare - and - Swap)和 synchronized 相结合的方式。对于读操作,大部分时候不需要加锁,直接通过数组和链表(或红黑树)获取数据,只有在扩容等特殊情况下才需要加锁。对于写操作,使用 synchronized 关键字锁住链表或红黑树的头节点,锁的粒度更细,进一步提升了并发性能。

不同读写比例场景下的选择

  1. 读多写少场景
    • ConcurrentHashMap:由于读操作大部分无需加锁,性能优势明显。在高并发读多写少的场景下,ConcurrentHashMap 能充分发挥其并发优势,减少线程等待时间,提高系统整体性能。
    • HashTable:因为每次读操作都要获取整个 HashTable 的锁,即使读操作之间不存在竞争,也会因为锁的存在而产生性能瓶颈,所以不适合读多写少场景。
  2. 写多读少场景
    • ConcurrentHashMap:在 JDK 1.8 中,写操作虽然采用了细粒度锁,但由于 CAS 操作和锁的竞争等因素,在写操作特别频繁时,可能会有一定的性能开销。不过相比 HashTable 整个表锁定的方式,ConcurrentHashMap 仍然具有一定优势,因为其锁粒度更细,多个写操作可以并行在不同的链表或红黑树头节点上进行。
    • HashTable:虽然每次写操作都锁定整个表,但如果写操作频率不高,并且对代码简洁性有一定要求(HashTable 实现相对简单),也可以考虑使用 HashTable。但总体来说,在写多读少的高并发场景下,ConcurrentHashMap 通常是更好的选择。