对ConcurrentHashMap的改造
jdk8对ConcurrentHashMap进行脱胎换骨的改造,使用大量的lock-free技术来减轻因锁的竞争而对性能造成的影响,涉及volatile,CAS,锁,链表,红黑色等众多知识点
jdk8版本的ConcurrentHashMap进行分析,它对jdk7进行版本改造了三点改造
- 取消分段锁机制,进一步降低冲突概率
- 引入红黑树结构,同一个哈希槽上的元素超过一定阀值(8)后,单向链表改为红黑树
- 使用了更加优化的方式统集合内的元素数量。首先,Map原有的size()方法最大只能表示2的31次方-1,ConcurrentHashMap额外提供了mappingCount(),用来返回集合内的元素数量,最大可以到达2的63次方-1,在元素更新时,使用了CAS和多种优化以提高并发能力
ConcurrentHashMap结构
数组存储结构分为两种:链表和红黑树。
(1)当某个槽内的元素超过8且table的容量大于或等于64时,由链表转为红黑树。
(2)当某个槽内的元素减少到6时,则由红黑素转换为链表。
(3)需要注意当table容量小于64只会扩容,并不会转换成红黑树
(4)再转换过程中,使用同步块锁住当前槽的首元素,防止其他进程对当前槽进行操作,转换完成后利用CAS替换原有链表(因为treeBin也存了next的引用,所以红黑树转链表变得非常简单,从TreeBin的first元素开始遍历所有节点,把节点从TreeNode转为Node即可)
链表转红黑树
触发上图主要操作时增加元素,即put()方法,基本思想与hashMap一致
扩容流程示意图
size()方法的优化
借助basrCount和countCells两个属性,并多次配合使用CAS方法,jdk8中的CouncurrentHashMap避免了锁的使用,思路分为:
- 当并发量少时,优先使用CAS的方式直接更新baseCount
- 如果更新base冲突,则认为会进入到比较激烈的竞争状态,通过启用counterCells减少竞争,通过CAS的方式把总数更新情况记录在conterCells对应的位置上
- 如果更新counterCells上某个对应的位置出现了多次失败,则会通过扩容counterCells的方式减少冲突
- 当conterCells处在扩容期间时,会尝试更新baseCount值
对于总数的统计,自需要让baseCount加上各个counterCells内的数据,就可以得出哈希内的元素总素,整个过程不需要借助锁。
- 更多内容请移驾至:个人主页