在ConcurrentHashMap的传输方法中,我不明白这两个条件的含义"i >= n"和"i + n >= nextn"



在transfer方法中,判断扩展终止(或帮助transfer线程完成(的条件为if (i < 0 || i >= n || i + n >= nextn) {。我知道i < 0这个条件意味着所有的仓位都已分配,但我不理解其他两个条件的含义:i >= ni + n >= nextn

i >= n是否考虑数据溢出?(-2147483648-1=2147483647(;

i + n >= nextni >= n一样吗?(我不这么认为(

private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
int n = tab.length, stride;
//...
int nextn = nextTab.length;
ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
boolean advance = true;
boolean finishing = false; // to ensure sweep before committing nextTab
for (int i = 0, bound = 0;;) {
Node<K,V> f; int fh;
while (advance) {
int nextIndex, nextBound;
if (--i >= bound || finishing)
advance = false;
else if ((nextIndex = transferIndex) <= 0) {
i = -1;
advance = false;
}
else if (U.compareAndSwapInt
(this, TRANSFERINDEX, nextIndex,
nextBound = (nextIndex > stride ?
nextIndex - stride : 0))) {
bound = nextBound;
i = nextIndex - 1;
advance = false;
}
}
if (i < 0 || i >= n || i + n >= nextn) {
int sc;
if (finishing) {
nextTable = null;
table = nextTab;
sizeCtl = (n << 1) - (n >>> 1);
return;
}
if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
return;
finishing = advance = true;
i = n; // recheck before commit
}
}
//...
}

从逻辑上讲,这是一段死代码,我认为这可能是在编码/解码过程中的边界判定。

从数学的角度来看,如果i>=n、 然后

  1. int溢出:不可能。因为最大调整大小阈值是1<lt;29、n的最大值是1<lt;29
  2. 我变得比n大:不可能。beacuse i=nextIndex-1,nextIndex=transferIndex,transferIndex=nextIndex步幅
    如果i>n、 则transferIndex需要由另一个线程更新为更大的值(加倍(。这意味着在当前调整大小尚未完成的情况下发生新的调整大小!
    这绝对不可能
while (advance) {
int nextIndex, nextBound;
if (--i >= bound || finishing)
advance = false;
else if ((nextIndex = transferIndex) <= 0) { //here is the only chance to update nextIndex
i = -1;
advance = false;
}
else if (U.compareAndSwapInt
(this, TRANSFERINDEX, nextIndex,
nextBound = (nextIndex > stride ?
nextIndex - stride : 0))) {
bound = nextBound;
i = nextIndex - 1;
advance = false;
}
}

人们可能会怀疑volatile变量的更新序列,例如nextTable/table/sizeCtl,也是不可能的。
因为在调整大小的最后,它们被更新如下:

//see the method transfer
if (finishing) {
nextTable = null;
table = nextTab;
sizeCtl = (n << 1) - (n >>> 1);
return;
}

并且所有传输的输入都严格检查表/nextTable/sizeCtl和transferIndex。
同样,没有办法泄露部分更新以进行传输。

因此i+n>=下一个

最新更新