目录
- 1.说明
- 2.基本结构
- 3.线程安全机制
- 3.1 分段锁
- 3.2 CAS操作
- 3.3 volatile关键字
- 4.扩容机制
- 5.其他特性
1.说明
- 1.ConcurrentHashMap是Java中的一个线程安全的哈希表实现。
- 2.ConcurrentHashMap的底层结构主要由数组、链表和红黑树组成。
- 3.在JDK 1.8及之后的版本中,ConcurrentHashMap使用这些数据结构来存储键值对,并通过散列算法来确定键值对在数组中的位置。
- 4.ConcurrentHashMap通过分段锁、CAS操作、volatile关键字机制来保证线程安全。
- 5.当ConcurrentHashMap中的元素数量超过一定阈值时,会触发扩容操作。
2.基本结构
- 1.数组:ConcurrentHashMap的初始数组长度通常为16(默认值),这个数组用于存储Node节点,每个Node节点包含一个key-value对。
- 2.链表:当多个键值对通过散列算法计算得到的索引相同时,它们会被存储在同一个数组位置上的链表中。在JDK 1.8中,链表使用尾插法插入新节点。
- 3.红黑树:当链表中的节点数量超过一定阈值(默认为8),并且数组长度大于64时,链表会转换为红黑树。红黑树的引入降低了数据查询的时间复杂度,从O(n)降低到O(logn)。
3.线程安全机制
3.1 分段锁
- 1.Segment Lock。
- 2.在JDK 1.7及之前的版本中,ConcurrentHashMap使用分段锁机制将整个哈希表分成多个段(Segment),每个段维护一个独立的锁。
- 3.不同的线程可以同时访问不同的段,提高了并发性能。
- 4.但在JDK 1.8及之后的版本中,虽然概念上仍然保留了分段锁的思想,但实际上是通过更细粒度的锁(如CAS操作和synchronized关键字对链表头节点的加锁)来实现的。
3.2 CAS操作
- 1.在JDK 1.8中,ConcurrentHashMap在更新元素时使用了无锁算法CAS(Compare-And-Swap),这是一种硬件级别的原子操作,可以确保在多线程环境下数据的正确性和一致性。
3.3 volatile关键字
- 1.ConcurrentHashMap中的数组(table)被volatile关键字修饰,这保证了在多线程环境下数组的可见性。
- 2.当一个线程修改了数组的内容时,其他线程可以立即看到这个修改。
4.扩容机制
- 1.计算新容量:根据当前的容量和负载因子计算出新的容量。
- 2.重新分配数组:创建一个新的数组,其长度为新容量的值。
- 3.数据迁移:将旧数组中的数据迁移到新的数组中。在JDK 1.8中,引入了多线程并发扩容的机制,多个线程可以同时对原始数组进行分片后,每个线程负责一个分片的数据迁移,从而提升了扩容过程中数据迁移的效率。
5.其他特性
- 1.不允许空键或空值:ConcurrentHashMap不允许键或值为空(null),如果尝试插入空键或空值,会抛出NullPointerException。
- 2.高效的读操作:由于ConcurrentHashMap的读操作是线程安全的,且不需要获取锁,因此读操作在没有竞争的情况下几乎没有性能损耗。
- 3.支持原子操作:ConcurrentHashMap提供了一些原子操作,如putIfAbsent、remove、replace等,这些操作可以在不需要额外的同步措施的情况下执行。