ConcurrentHashMap的并发利器:分段锁与CAS机制
ConcurrentHashMap是Java集合框架中高性能的并发HashMap实现,它通过精巧的设计在保证线程安全的同时,提供了远高于Hashtable和SynchronizedMap的并发性能。其核心优势在于摒弃了传统的粗粒度锁,采用了分段锁(Segment)和CAS(Compare-And-Swap)等机制,实现了更细粒度的并发控制。
内部结构演进:从分段锁到CAS+synchronized
在JDK 1.7及之前,ConcurrentHashMap采用分段锁机制,将整个哈希表分成多个Segment(默认为16个),每个Segment独立加锁。这种设计允许多个线程同时访问不同的Segment,从而提高了并发度。然而在JDK 1.8中,ConcurrentHashMap进行了重大重构,放弃了分段锁设计,转而采用Node数组+链表+红黑树的数据结构,并发控制则通过CAS操作和synchronized关键字实现,进一步提升了性能。
核心并发控制机制
JDK 1.8版本的ConcurrentHashMap主要依赖三种机制实现线程安全:1) CAS操作用于无竞争情况下的快速节点插入;2) synchronized关键字用于锁定单个桶(链表头节点或红黑树根节点);3) volatile关键字保证变量的可见性。这种设计将锁的粒度从多个段缩小到单个桶,显著减少了锁竞争,提高了并发性能。
扩容机制的高明之处
ConcurrentHashMap的扩容机制设计十分精巧。当需要扩容时,它并不一次性完成所有数据迁移,而是采用分治策略,逐步将节点从旧数组转移到新数组。多个线程可以协同参与扩容过程,每个线程负责迁移一部分桶。这种设计避免了长时间的停顿,保证了在扩容期间仍然可以提供读服务(读操作无需加锁),只有涉及被迁移桶的写操作需要等待。
大小统计的优化策略
ConcurrentHashMap摒弃了传统的大小变量AtomicInteger,采用了CounterCell数组来统计元素数量。当多个线程同时更新大小时,每个线程可以更新不同的CounterCell,最后求和得到总大小。这种方法避免了单一原子变量的争用,提高了高并发场景下的性能表现,是分而治之思想的又一体现。
迭代器的弱一致性保证
ConcurrentHashMap的迭代器提供弱一致性保证,而非fail-fast机制。这意味着迭代器反映的是创建迭代器时或之后某个时间点的哈希表状态,不会抛出ConcurrentModificationException。这种设计允许在迭代过程中进行并发修改,适用于大多数并发场景,是实现高吞吐量的重要因素。
应用场景与最佳实践
ConcurrentHashMap特别适合读多写少的并发场景,是实现高并发缓存、共享数据存储的理想选择。在实际使用中,应尽量避免使用锁整个表的方法(如size()可能不精确),而应优先使用并发友好的方法(如mappingCount())。合理的初始容量和负载因子设置也能有效减少扩容次数,提升性能。
606

被折叠的 条评论
为什么被折叠?



