Java7 中ConcurrentHashMap工作原理详解
Java 7的ConcurrentHashMap
采用了分段锁(Segmentation Lock)的机制来实现高并发。由一个Segment数组和多个HashEntry组成。Segment数组的意义就是将一个大的table分成很多小table来进行加锁,每一个Segment元素存储的是HashEntry数组+链表。
一、基本结构
在Java 7中,ConcurrentHashMap
的底层结构是由一个Segment
数组和多个HashEntry
组成的链表(但Java 7中并未引入红黑树优化)构成。每个Segment
本质上是一个小型的HashMap
,它包含了一个HashEntry
数组和一些控制信息,如锁、元素数量等。
二、分段锁
ConcurrentHashMap
通过将整个Map分为多个Segment
,每个Segment
都有一把锁,来实现细粒度的并发控制。当线程需要访问某个Segment
时,它必须先获得该Segment
的锁,然后就可以安全地进行读写操作,而不会干扰其他线程对其他Segment
的访问。
Segment继承了ReentrantLock,它每次找HashEntry使用重入锁的tryLock(),如果获取锁成功则直接插入相应位置,若是失败会以自旋方式继续尝试,直到超过指定次数,被挂起。
三、HashEntry
HashEntry
是ConcurrentHashMap
中用于存储键值对的基本单元。每个HashEntry
都包含了一个键、一个值、一个指向下一个HashEntry
的引用和一个哈希值。在Java 7中,HashEntry
组成的链表用于解决哈希冲突。
四、读写操作
在Java 7的ConcurrentHashMap
中,读操作不需要获取锁,因为整个Map被分成了多个Segment
,每个Segment
之间是相互独立的。因此,多个线程可以同时进行读操作而不会相互干扰。
由于HashEntry的value变量是 volatile的,也能保证读取到最新的值
写操作(包括插入、删除和更新)则需要先获取对应Segment
的锁。当线程获得了锁之后,就可以安全地进行写操作,而其他线程如果需要访问同一个Segment
,则会被阻塞直到锁被释放。
五、扩容
当ConcurrentHashMap
中的元素数量达到某个阈值时,会触发扩容操作。在Java 7中,扩容操作也是分段进行的。每个Segment
都可以独立地进行扩容,这样可以减少扩容过程中的线程阻塞。
总结
Java 7中的ConcurrentHashMap
通过分段锁的机制实现了高并发的读写操作。它将整个Map分成了多个Segment
,每个Segment
都有一把锁,从而实现了细粒度的并发控制。读操作不需要获取锁,而写操作则需要先获取对应Segment
的锁。这种设计使得ConcurrentHashMap
在并发场景下具有较高的性能。然而,需要注意的是,在Java 8及以后的版本中,ConcurrentHashMap
的实现进行了一些改进和优化,如引入了红黑树和使用了CAS操作等。
参考
https://blog.csdn.net/qq_40198004/article/details/89047318