高并发神器!ConcurrentHashMap为何如此高效

引言

大家好,我是小米!当天我们来聊聊Java中一个超级适用的线程安选汇合类——ConcurrentHashMap。关于多线程环境中须要频繁读写数据的场景来说,ConcurrentHashMap无疑是个好帮手。那么,为什么ConcurrentHashMap效率高?底层成功的微妙又是什么?接上去,让我们一探求竟。

ConcurrentHashMap与Hashtable的对比

在多线程环境中,我们经常须要保障数据的线程安保性。说到成功线程安保,ConcurrentHashMap和Hashtable都是不错的选用,但二者的性能体现却有很大差异。

Hashtable:同步锁的性能瓶颈

Hashtable作为Java早期的线程安保类,关键经过Synchronized关键字启动方法级别的同步来保障线程安保。比如,在口头put或get操作时,Hashtable会锁住整个对象,造成同一期间只能有一个线程访问或修负数据。这样虽然保障了安保性,但性能相对低下。

ConcurrentHashMap:分段锁的高效设计

ConcurrentHashMap的外围现实是分段锁,这使得它在性能上要远优于Hashtable。便捷来说,ConcurrentHashMap将数据划分红多个段(Segment),每个Segment对应一个锁。不同线程访问不同Segment的数据时,可以同时启动而不相互阻塞,从而提高了并发性能。

Java的两个关键版本(1.7和1.8)对ConcurrentHashMap的底层结构有很大的差异,我们一同来看看它们的演化环节。

JDK 1.7:Segment分段锁

在JDK 1.7中,ConcurrentHashMap经常使用了分段锁(Segment)的设计。经过这一设计,ConcurrentHashMap到达了提高并发访问率的成果。

底层结构:Segment数组 + HashEntry链表

ConcurrentHashMap在底层将数据分为多个Segment,每个Segment外部由链表存储数据。这样一来,ConcurrentHashMap将整个Map分红了若干个小的子Map,每个Segment相当于一个小的Hashtable,持有一个独立的锁。因此,多个线程访问不同Segment的元素时不会相互影响,从而提高了并发性能。

如何成功分段锁?

ConcurrentHashMap中会对每一个键值对启动哈希计算,以确定它属于哪个Segment。每个Segment锁住一个区域的数据,这样每次只锁定一个Segment,即使一个Segment被锁定,其余Segment也可以同时被访问,这就防止了整个Map锁住的低效状况。

优缺陷

JDK 1.8:无Segment,链表+红黑树+CAS

JDK 1.8中,ConcurrentHashMap的底层结构和成功模式出现了严重变动,Segment不再存在,取而代之的是更为精简的成功模式。JDK 1.8摒弃了Segment锁机制,而是驳回了数组+链表+红黑树的组合数据结构。

数据结构:Node数组 + 链表/红黑树

JDK 1.8的ConcurrentHashMap与1.8版本的HashMap十分相似,底层经过一个Node数组来存储数据。假设某个桶中有少量hash抵触的数据,会先构成链表;当链表长度超越必定阈值(8)后,会转化成红黑树结构,从而提高查问效率。

并发控制:CAS + synchronized

ConcurrentHashMap 1.8 的线程安保关键经过CAS(Compare And Swap)和synchronized关键字来成功,而不是之前的锁住整个Segment。这样在启动增删改查时,只有要锁住操作的链表头部节点即可,大大降落了锁的粒度,进一步优化了并发效率。

优缺陷

ConcurrentHashMap的外围机制剖析

1. get操作

get操作在ConcurrentHashMap中是无锁的,关键经过定位到详细的Node节点来间接失掉数据。

流程:

2. put操作

在口头put时,ConcurrentHashMap会尝试经常使用CAS来参与元素。假设节点位置为空,CAS降级会成功;否则,系统会退而经常使用synchronized锁住节点启动降级操作。

流程:

若为链表,遍历链表并参与至末尾;链表长度超越8则转化为红黑树。

若为红黑树,则依照红黑树的拔出规定启动降级。

3. 扩容机制

与HashMap相似,ConcurrentHashMap在容量无余时会启动扩容。不同的是,ConcurrentHashMap的扩容操作是分段启动的。

ConcurrentHashMap的优势总结

ConcurrentHashMap作为Java中一个关键的并发汇合类,仰仗其分段锁和CAS机制,在保障线程安保的同时,大大优化了性能。JDK 1.7中经过Segment的分段锁来降落锁竞争,而JDK 1.8中则进一步改良为无锁化操作和红黑树的结构,大幅度优化了性能和并发性。

在实践开发中,假设你须要一个线程安保、高并发的Map汇合,ConcurrentHashMap相对是一个值得信任的选用!宿愿当天的分享能够协助大家更好地理解ConcurrentHashMap的底层设计及其优势,我们下次再一同讨论更多Java黑科技!

您可能还会对下面的文章感兴趣: