【153、ConcurrentHashMap底层,为什么能并发,get、put怎么并发安全的,哈希冲突有哪些解决方法?】

79 阅读2分钟

ConcurrentHashMap 是 Java 并发包中提供的一个线程安全的哈希表,相较于普通的 HashMap,它支持高并发的读和写操作。其底层实现采用了分段锁(Segment)和 CAS 算法,对于不同的数据段加锁,提高了并发度。

在 ConcurrentHashMap 中,数据结构和 HashMap 基本相同,不同点在于数据结构的实现和线程安全的实现方式。它的底层实现采用了一个数组+链表/红黑树的结构来存储数据,将整个哈希表分为多个段(Segment),每个段独立地加锁。每个段内部的操作都是线程安全的,多个线程同时对不同段进行操作不会相互影响。

ConcurrentHashMap 的 put、get 操作采用了类似于分段锁的方式,即将整个哈希表分成多个段,每个段上单独进行加锁,这样可以最大程度地提高并发度。当需要进行扩容时,因为只需要对某个段进行扩容,所以不需要对整个哈希表进行扩容,减少了线程冲突的可能性。

在哈希冲突的情况下,ConcurrentHashMap 采用了链表和红黑树两种结构来解决。具体来说,在进行 put 操作时,如果发现某个位置已经有元素了,会采用链表的方式将元素添加到链表的尾部;如果链表长度超过了阈值,链表就会被转化成红黑树。在进行 get 操作时,首先会进行哈希定位,然后根据哈希值查找对应的段,然后再在段内部查找元素,如果链表长度超过了阈值,就会通过红黑树的方式进行查找。

至于为什么红黑树的阈值是 8,这是由于在经过大量的测试后发现,链表长度为 8 时,将链表转化为红黑树的效果最好。如果阈值设置得太小,可能会频繁地进行链表和红黑树的转化,导致效率降低;如果阈值设置得太大,可能会导致链表长度过长,查找效率降低。因此,经过多次实验,ConcurrentHashMap 的阈值被设置为了 8。