巅峰战队|ConcurrentHashMap的部分源码分析
1.ConcurrentHashMap是线程安全的 , size()和mappingCount()有什么区别呢?经查源码 , 可看到
经比较分析得出:二者返回值不同 , 为什么会这样?查看英文注释得知 , 高并发下 , 如果同时存在insert、remove时 , 可能会出现不一致 , 所以推荐使用mappingCount() 。
int的范围是 -2^31——2 ^31-1
long的范围是 -2^63——2 ^63-1
2.它在高并发下是怎么保证扩容的?它的扩容方法是transfer()
【巅峰战队|ConcurrentHashMap的部分源码分析】代码非常酷 , 令人赞叹!该方法的执行逻辑如下:1.通过计算 CPU 核心数和 Map 数组的长度得到每个线程(CPU)要帮助处理多少个桶 , 并且这里每个线程处理都是平均的 。 默认每个线程处理 16 个桶 。 因此 , 如果长度是 16 的时候 , 扩容的时候只会有一个线程扩容 。
2.初始化临时变量 nextTable 。 将其在原有基础上扩容两倍 。
3.死循环开始转移 。 多线程并发转移就是在这个死循环中 , 根据一个 finishing 变量来判断 , 该变量为 true 表示扩容结束 , 否则继续扩容 。
3.1 进入一个 while 循环 , 分配数组中一个桶的区间给线程 , 默认是 16. 从大到小进行分配 。 当拿到分配值后 , 进行 i-- 递减 。 这个 i 就是数组下标 。 (其中有一个 bound 参数 , 这个参数指的是该线程此次可以处理的区间的最小下标 , 超过这个下标 , 就需要重新领取区间或者结束扩容 , 还有一个 advance 参数 , 该参数指的是是否继续递减转移下一个桶 , 如果为 true , 表示可以继续向后推进 , 反之 , 说明还没有处理好当前桶 , 不能推进)3.2 出 while 循环 , 进 if 判断 , 判断扩容是否结束 , 如果扩容结束 , 清空临时变量 , 更新 table 变量 , 更新库容阈值 。 如果没完成 , 但已经无法领取区间(没了) , 该线程退出该方法 , 并将 sizeCtl 减一 , 表示扩容的线程少一个了 。 如果减完这个数以后 , sizeCtl 回归了初始状态 , 表示没有线程再扩容了 , 该方法所有的线程扩容结束了 。 (这里主要是判断扩容任务是否结束 , 如果结束了就让线程退出该方法 , 并更新相关变量) 。 然后检查所有的桶 , 防止遗漏 。 3.3 如果没有完成任务 , 且 i 对应的槽位是空 , 尝试 CAS 插入占位符 , 让 putVal 方法的线程感知 。 3.4 如果 i 对应的槽位不是空 , 且有了占位符 , 那么该线程跳过这个槽位 , 处理下一个槽位 。 3.5 如果以上都是不是 , 说明这个槽位有一个实际的值 。 开始同步处理这个桶 。 3.6 到这里 , 都还没有对桶内数据进行转移 , 只是计算了下标和处理区间 , 然后一些完成状态判断 。 同时 , 如果对应下标内没有数据或已经被占位了 , 就跳过了 。
4.处理每个桶的行为都是同步的 。 防止 putVal 的时候向链表插入数据 。 4.1 如果这个桶是链表 , 那么就将这个链表根据 length 取于拆成两份 , 取于结果是 0 的放在新表的低位 , 取于结果是 1 放在新表的高位 。 4.2 如果这个桶是红黑数 , 那么也拆成 2 份 , 方式和链表的方式一样 , 然后 , 判断拆分过的树的节点数量 , 如果数量小于等于 6 , 改造成链表 。 反之 , 继续使用红黑树结构 。 4.3 到这里 , 就完成了一个桶从旧表转移到新表的过程 。
- 大河客户端|布局战队,导师各有妙招,《2020中国好声音》收视率蝉联第一
- 周到|“好声音”蝉联省级卫视综艺节目收视第一,首迎抢位战导师布局战队各有妙招
- 综艺|靠师兄“上位”,出道即巅峰,她光环加身却依旧是糊咖
- 王者荣耀|王者重开机制揭秘:钻石段位以上必看,五战士,四辅助可重开,巅峰赛不能
- 杜兰特|83投60中!比巅峰杜兰特还强,季后赛最强球星出现了
- 青年|射手梯度排名更新,又一无解T0诞生,张大仙我愿称他为射手巅峰
- 通天战队|A股最励志闻泰科技!给华为小米打工到半导体巨头,半年赚17亿
- |《街舞3》火舞台battle开启 钟汉良战队团魂之力势不可挡
- |《这!就是街舞》第三季火舞台热力喷发,队长领衔齐舞大秀燃炸战队之魂
- 环球网|美海军陆战队一架CH-53E紧急迫降 未造成人员伤亡