ConcurrentHashMap
2020-11-01 02:33:43 0 举报
ConcurrentHashMap
作者其他创作
大纲/内容
i < 0 || i >= n || i + n >= nextn分支1:表示超出桶数区间范围,根据不同情况结束
根据取到的区间(bound~i)
if (tab == null || (n = tab.length) == 0)第一次添加元素时命中,因为table是懒加载初始化完成之后,继续此循环
所以:这个方法的精妙之处结合CPU核树对线程的控制:如果1核,区间直接包括所有;如果多核,保证没个线程每次最少处理16个的基础上,总桶数 / 8 / NCPU,不直接除以NCPU是为了确保任务分配均匀吧赋值和条件判断精简了代码,但是增加了阅读障碍;良好的控制让线程每次先竞争扩容资格桶数区间,区间窗口的移动也值得细品。争取到之后循环处理,CAS成功或者失败重试处理得很自然(状态变动平滑)sizeCtrl的极致应用:可以存下一次触发扩容的元素个数;可以存储扩容状态、扩容前数量(通过前置0统计降级数量级)、扩容线程数量table和nextTable的结合使用,使扩容时更加平稳多线程扩容时保证最后统一提交
不同情况
tab = initTable();
树fh = -2使用 f instanceof TreeBin 判断
return null
int binCount = 0;hash冲突标记
树化处理
节点类型
else进入这里说明f、i、fh都被赋值了其他情况,桶位上有节点,节点是链表,也可能是树;key可能存在,也可能不存在V oldVal = null;
添加节点
int hash = spread(key.hashCode()); 兼顾高低位Hash并保证位正数;
(fh = f.hash) == MOVED分支3:进入这个判断肯定经过了2:此时f不为空,如果f的hash为MOVED表示这个被移动过了,跳过,进入下一个循环advance = true;
if (key == null || value == null) throw new NullPointerException();校验:键值都不可为空
链表fh >= 0
true,此时binCount = 0
else经过了分支2、3节点取出来了f,hash也取出来了 fh,有两种情况,此节点可能是链表,也可能是树
if (nextTab == null) { // initiating try { @SuppressWarnings(\"unchecked\
这是一个死循环XX,先获取当前线程应该处理的桶数区间。然后根据不同情况进行移动:因为在这过程中可能有其他线程处理或者干扰,所以用死循环来保证,如果本次失败,就重新来过
if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE) { stride = MIN_TRANSFER_STRIDE;}计算每核(线程)最多处理几个桶:最少16个;如果是单核,所有桶都交给一个线程来处理,所以stride = n;如果是多核,总桶数 / NCPU理论上是每个线程(核)理想处理数,但是先 >>> 3 即 除以8,这样一核可以支持8线程?如果没有那么多线程,就循环分几次完成
收藏
收藏
0 条评论
下一页