<=0 说明任务已经迁移任务已经分配完了 。if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||transferIndex <= 0)// 处于扩容状态,且扩容已经结束 or 扩容的线程达到最大值,则没必要帮助扩容break;// 帮助扩容的线程+1if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))transfer(tab, nt);}// 2. 第一个触发扩容的线程// (rs << RESIZE_STAMP_SHIFT) + 2,为什么加2呢// 1000000000011001 0000 0000 0000 0000 + 2// sc = 1000000000011001 0000 0000 0000 0010else if (U.compareAndSwapInt(this, SIZECTL, sc,(rs << RESIZE_STAMP_SHIFT) + 2))transfer(tab, null);// 3. 第一个扩容线程没有触发成功,则重新统计元素总个数,再循环一次 。s = sumCount();}}}
刚才计算的元素总个数s >= sc扩容的阈值,并且tab的地址没有改变,并且数组的长度没有达到最大值则触发扩容 。
(1)计算过程
rs是什么意思,有什么作用?刚开始就被一块石头绊住了 。那就来先看看(n)的计算过程:
/*** 返回值作为正在扩容的数据表的size即n的一个标志,rs可以反推出n* Returns the stamp bits for resizing a table of size n.* Must be negative when shifted left by RESIZE_STAMP_SHIFT.**/static final int resizeStamp(int n) {return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));}
看源码注释,返回值作为正在扩容数组的长度n的一个标志位?并且当向左移=16位时得到一个负数?
.(n)的作用是获取n的二进制从左往右连续的0的个数,比如:
2的二进制10从左往右有30个连续的04的二进制100从左往右有29个连续的08的二进制1000从左往右有28个连续的016的二进制10000从左往右有27个连续的0(int有32位,左边不足的补0)
(1 >> ) != rs判断当前数组是否在扩容状态,也是可以判断扩容是否结束的,扩容真的结束了,sc会修改为新数组的扩容阈值,自然就不处于扩容状态了,只是会使得一些线程参与到了扩容中却发现结束了(逻辑虽然不严谨,但是对项目运行性能的影响也不大) 。
既然是bug,后面的版本应该会修复这个bug吧,找到还没修复,找到看样子修复了:
(3)元素迁移
不管第一个扩容线程还是帮助线程都会调用,顾名思义,转移,从旧数组转移到新数组的过程 。这个过程中涉及到扩容线程任务的分配和元素的复制迁移 。(吐槽一下官方源码,一个函数代码长就算了,if-else还很多,在实际开发中,讲究一个去else化,能及时返回就及时返回,搞这么多else分支,还互相嵌套,可读性很差诶 。)
注释很清楚,虽然长,情况又多,反复琢磨几遍,明白作者的意图,就觉得还行,是人的思维 。
private final void transfer(Node
- 中国5个最有特色的摩天轮第四个独一无二第五个世界最高 中国之最摩天轮
- 徐静雨:现役中库里排第二杜兰特只能排第三,这排名非常不严谨 徐静雨各个位置历史之最
- 火影忍者十大瞳术排行榜:轮墓·边狱只能排第二 世界十大瞳术
- 湖二师学子三下乡:素描画中国 中国之最简单画法
- 塞纳当选F1过去四十年最快车手!舒马赫、汉密尔顿分列二三 f1历史之最车手排位
- H5云商城源码全新UI|支持易支付v1.0【个人开发全网首发】
- 二 自动化测试 - RFT系列教程4: RFT是如何识别控件的 对象库与脚本
- 清朝十二帝:揭光绪帝和他的四个男人之谜
- 来涨姿势了,可能有用并使你才识渊博的冷知识来袭 二 跳远的吉尼斯记录
- 七十二景