ConcurrentHashMap 属于 Java 的 java.util.concurrent(JUC)并发包。
JUC(java.util.concurrent)包是 Java 中用于处理并发编程的核心工具包。它提供了一系列高效、灵活且线程安全的类和接口,帮助开发者解决多线程环境下数据共享和同步的问题。在现代多核处理器的背景下,有效地利用并发编程可以显著提高程序的性能,而 JUC 包就是实现这一目标的关键所在。
在Java的并发编程世界里,ConcurrentHashMap和红黑树都是极为重要的元素。特别是在JDK 1.8中,ConcurrentHashMap的实现有了重大升级,与红黑树的结合使其在处理高并发场景时更加高效和灵活。
一、JDK 1.8中的ConcurrentHashMap
(一)数据结构
- 总体结构
- JDK 1.8的ConcurrentHashMap以数组作为基础结构,数组的每个元素(桶)可以容纳链表或者红黑树。这种混合结构是应对复杂并发数据处理的关键。
- 数组的初始容量默认为16,并且其长度始终保持为2的幂次方。这一设计巧妙之处在于,计算元素在数组中的位置时,可以利用位运算(
&
操作)而非相对较慢的取模运算。具体而言,计算索引的公式为tabAt(tab, i = (n - 1) & hash)
,其中tab
是数组,n
是数组长度,hash
是键的哈希值。
- 链表与红黑树部分
- 当多个键经哈希计算后对应到同一个数组索引位置时,它们会以链表形式存储在该桶内。然而,当链表长度超过阈值(默认为8)时,链表会升级为红黑树。这一转换的核心目的是提升查询效率。因为链表的查找时间复杂度为O(n)O(n)O(n),而红黑树仅为O(logn)O(log n)O(logn)。
(二)并发控制机制
- 锁分段机制的改进
- 在JDK 1.7中,ConcurrentHashMap采用分段锁(Segment)机制实现并发控制,每个Segment有独立的锁,不同Segment间可并发访问。但JDK 1.8采用了更细粒度的锁策略。如今,只有在对数组中的某个桶进行操作且发生冲突时才会加锁。例如,在执行
put
操作时,会先尝试使用CAS(比较并交换)操作无锁更新元素,若CAS失败,表明存在并发冲突,此时才加锁处理。
- 在JDK 1.7中,ConcurrentHashMap采用分段锁(Segment)机制实现并发控制,每个Segment有独立的锁,不同Segment间可并发访问。但JDK 1.8采用了更细粒度的锁策略。如今,只有在对数组中的某个桶进行操作且发生冲突时才会加锁。例如,在执行
- 安全的并发读写操作
- 读取操作多数情况下无需加锁。这得益于数组元素(桶)以及链表、红黑树节点都被声明为
volatile
,从而确保了数据的可见性。多个线程可同时读取数据且不会出现数据不一致问题。而在写入操作时,如put
方法,先依据哈希算法定位桶,再借助Unsafe
类的compareAndSwapObject
等方法尝试无锁写入。仅当并发冲突严重时才使用锁来保障操作的原子性。
- 读取操作多数情况下无需加锁。这得益于数组元素(桶)以及链表、红黑树节点都被声明为
(三)应用场景
- 高并发缓存系统
- 可作为缓存系统底层数据结构。在分布式缓存系统中,多节点可能同时读写缓存数据,ConcurrentHashMap能高效处理并发请求,维护缓存数据一致性。
- 多线程环境下的共享数据存储
- 在多线程应用里,用于存储共享配置信息或全局计数器等数据。例如Web服务器中统计各请求路径访问次数,多线程可同时更新而无冲突。
二、红黑树
(一)红黑树的性质
- 节点颜色规则
- 红黑树是自平衡二叉查找树,节点非红即黑。根节点为黑色,所有叶子节点(NIL节点,空节点)亦为黑色。并且,若一个节点为红色,其两个子节点必定为黑色(即从叶子到根的路径上不能有连续两个红色节点)。
- 高度平衡特性
- 从根节点到任意叶子节点的最长路径长度不会超过最短路径的两倍。此平衡特性确保了红黑树的查找、插入和删除操作时间复杂度均为O(logn)O(log n)O(logn)。例如,对于含n个节点的红黑树,查找一个节点最多只需log2nlog_2nlog2n次比较操作。
(二)红黑树的操作
- 插入操作
- 插入新节点时,先依二叉查找树规则置于合适位置。随后,为维持红黑树性质,可能需进行颜色调整与旋转操作。比如,若插入的新节点父节点为红色,就会违反红黑树规则,此时需通过变色和旋转恢复平衡。
- 删除操作
- 删除操作较为复杂。首先定位要删除的节点,再依其子节点情况处理。若待删节点有两个子节点,通常用其中序后继节点替换它,然后删除后继节点。删除后,同样可能需颜色调整与旋转操作以保持红黑树平衡。
- 查找操作
- 查找操作类似普通二叉查找树。从根节点起始,比较查找键与当前节点键值。若相等则找到目标;若查找键小于当前节点键,则向左子树查找;若大于则向右子树查找。因红黑树平衡特性,查找时间复杂度为O(logn)O(log n)O(logn)。
(三)在ConcurrentHashMap中的应用
- 提高性能
- 在ConcurrentHashMap中,长链表场景下查找元素效率低下(时间复杂度O(n)O(n)O(n)),而红黑树查找时间复杂度为O(logn)O(log n)O(logn)。当大量数据哈希至同一桶时,转换为红黑树可大幅提升定位键值对的速度。
- 并发友好的结构调整
- 进行链表转红黑树及红黑树平衡调整时,ConcurrentHashMap采用并发安全机制。如结构转换过程中,利用锁或CAS操作确保转换原子性,使多线程环境下数据结构转换与维护得以正确进行。
无论是处理高并发缓存还是多线程共享数据,ConcurrentHashMap都为我们提供了强大的工具和坚实的基础。