ConcurrentHashMap的性能之所以比HashTable好,主要归因于以下几个关键设计差异:
-
锁的粒度不同:
-
HashTable:使用的是传统的线程同步机制,即在整个HashTable上加锁(使用
synchronized关键字)。这意味着在同一时刻,只能有一个线程能够执行写操作,即使读操作也要互斥等待。这导致在高并发环境下性能大幅度降低,因为所有操作必须串行执行。 -
ConcurrentHashMap:采用了**分段锁(Segmentation)**的设计思想。在Java 7及以前的版本中,ConcurrentHashMap将数据划分为多个Segment(默认为16个),每个Segment都继承自ReentrantLock,因此当对一个Segment进行写操作时,只会锁住这个Segment,其他Segment可以继续服务读写请求。这极大地减少了锁的竞争,提高了并发能力。在Java 8及以后,虽然Segment的概念被摒弃,转而使用更精细的CAS(Compare-and-Swap)操作加上若干个锁粒度更细的Node,但核心思想依然是减少锁的范围,提高并发度。
-
-
读操作无锁:
- 在ConcurrentHashMap中,读取操作通常是无锁的,这意味着读取可以和写入操作并行进行,进一步提升了并发读的性能。
-
扩容机制:
- HashTable在扩容时需要锁定整个表,这是一个耗时的操作,会导致所有线程阻塞。
- ConcurrentHashMap在Java 7中采用了一种称为增量扩容的技术,即使在扩容过程中也能保证一定程度上的并发读写。而在Java 8中,更是优化了这一过程,通过CAS操作和新的节点插入逻辑,几乎实现了并发扩容,极大地减少了扩容带来的性能影响。
-
现代CPU架构优化:
- ConcurrentHashMap的设计考虑到了现代多核处理器的特性,通过减少伪共享(False Sharing)等问题,更好地利用了硬件资源。
综上所述,由于采用了更先进的并发控制技术和细粒度的锁设计,ConcurrentHashMap能够在多线程环境中提供更高的吞吐量和更低的延迟,因此其性能优于传统的HashTable。