// 将 transferIndex 值赋给 nextIndex
// 这里 transferIndex 一旦小于等于 0,说明原数组的所有位置都有相应的线程去处理了
else if ((nextIndex = transferIndex) <= 0) {
i = -1
advance = false
}
else if (U.compareAndSwapInt
(this, TRANSFERINDEX, nextIndex,
nextBound = (nextIndex > stride ?
nextIndex - stride : 0))) {
// 看括号中的代码,nextBound 是这次迁移任务的边界,注意,是从后往前
bound = nextBound
i = nextIndex - 1
advance = false
}
}
if (i < 0 || i >= n || i + n >= nextn) {
int sc
if (finishing) {
// 所有的迁移操作已经完成
nextTable = null
// 将新的 nextTab 赋值给 table 属性,完成迁移
table = nextTab
// 重新计算 sizeCtl: n 是原数组长度,所以 sizeCtl 得出的值将是新数组长度的 0.75 倍
sizeCtl = (n << 1) - (n >>> 1)
return
}
// 之前我们说过,sizeCtl 在迁移前会设置为 (rs << RESIZE_STAMP_SHIFT) + 2
// 然后,每有一个线程参与迁移就会将 sizeCtl 加 1,
// 这里使用 CAS 操作对 sizeCtl 进行减 1,代表做完了属于自己的任务
if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
// 任务结束,方法退出
if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
return
// 到这里,说明 (sc - 2) == resizeStamp(n) << RESIZE_STAMP_SHIFT,
// 也就是说,所有的迁移任务都做完了,也就会进入到上面的 if(finishing){} 分支了
finishing = advance = true
i = n
}
}
// 如果位置 i 处是空的,没有任何节点,那么放入刚刚初始化的 ForwardingNode ”空节点“
else if ((f = tabAt(tab, i)) == null)
advance = casTabAt(tab, i, null, fwd)
// 该位置处是一个 ForwardingNode,代表该位置已经迁移过了
else if ((fh = f.hash) == MOVED)
advance = true
else {
// 对数组该位置处的结点加锁,开始处理数组该位置处的迁移工作
synchronized (f) {
if (tabAt(tab, i) == f) {
Node<K,V> ln, hn
// 头节点的 hash 大于 0,说明是链表的 Node 节点
if (fh >= 0) {
// 下面这一块和 Java7 中的 ConcurrentHashMap 迁移是差不多的,
// 需要将链表一分为二,
// 找到原链表中的 lastRun,然后 lastRun 及其之后的节点是一起进行迁移的
// lastRun 之前的节点需要进行克隆,然后分到两个链表中
int runBit = fh & n
Node<K,V> lastRun = f
for (Node<K,V> p = f.next
int b = p.hash & n
if (b != runBit) {
runBit = b
lastRun = p
}
}
if (runBit == 0) {
ln = lastRun
hn = null
}
else {
hn = lastRun
ln = null
}
for (Node<K,V> p = f
int ph = p.hash
if ((ph & n) == 0)
ln = new Node<K,V>(ph, pk, pv, ln)
else
hn = new Node<K,V>(ph, pk, pv, hn)
}
https://www.laipuhuo.com/0145c6c01d184cea8e0be6062f1b86e8.html
https://www.laipuhuo.com/013e9ffdf507465880072a88b4d6f0ee.html
https://www.laipuhuo.com/013e83953be149e087b57f596cbaf5d2.html
https://www.laipuhuo.com/013DA7DD55FF4D24A6967F5CF115341F.html
https://www.laipuhuo.com/articlePage/9ce264a3-f868-4484-a8aa-6bb276cd3ad3.html
https://www.laipuhuo.com/articlePage/e589e5ea-3881-42a0-9cf4-b6d3aaa14cf4.html
https://www.laipuhuo.com/articlePage/cbfdf3c2-0f56-4173-ba19-4f6e6305228a.html
https://www.laipuhuo.com/articlePage/c2110711-f84d-48d2-9e72-2c2e99d5069d.html
https://www.laipuhuo.com/articlePage/ec0e6b70-c10c-456a-930e-ac9a189baea1.html
https://www.laipuhuo.com/articlePage/7606d5f5-fcb9-4468-930f-3c80dd18dbce.html
// 其中的一个链表放在新数组的位置 i
setTabAt(nextTab, i, ln)
// 另一个链表放在新数组的位置 i+n
setTabAt(nextTab, i + n, hn)
// 将原数组该位置处设置为 fwd,代表该位置已经处理完毕,
// 其他线程一旦看到该位置的 hash 值为 MOVED,就不会进行迁移了
setTabAt(tab, i, fwd)
// advance 设置为 true,代表该位置已经迁移完毕