本次ConcurrentHashMap的源码解析是针对JDK8,内容比较多,具体大纲请见下方截图:
public V put(K key, V value) {
return putVal(key, value, false);
}
final V putVal(K key, V value, boolean onlyIfAbsent) {
... ...
for (Node<K,V>[] tab = table;;) {
... ...
if (tab == null || (n = tab.length) == 0) {
tab = initTable();
}
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))) {
break;
}
}
else if ((fh = f.hash) == MOVED) {
tab = helpTransfer(tab, f);
}
else {
V oldVal = null;
synchronized (f) {
... 针对f链表或红黑树进行添加Node节点操作,执行完毕后break ...
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD) {
treeifyBin(tab, i);
}
if (oldVal != null) {
return oldVal;
}
break;
}
}
}
addCount(1L, binCount);
return null;
}
第一部分:首先开启了无限循环,在里面进行了4中情况的判断。
如果table数组为null或者长度为0,则创建table数组。
创建Node节点,插入到这个位置
加入到迁移大军中,帮助一起进行扩容迁移操作。
将节点插入到链表中或者红黑树中。
如果链表长度
第二部分:执行addCount,将ConcurrentHashMap中存储的k,v总数+1。
while ((tab = table) == null || tab.length == 0)
private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
if ((sc = sizeCtl) < 0) {
Thread.yield(); // 其他竞争失败的线程,会在while循环中spin,直到table创建完毕才能跳出while循环
}
else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
... 只有一个线程可以成功执行CAS操作,将sizeCtl赋值为-1 ...
... 执行创建table数组操作 ...
}
}
return tab; // 返回创建好的table数组
}
ABASE = U.arrayBaseOffset(ak);
如果scale=8(十进制)=1000(二进制)
那么计算出Integer.numberOfLeadingZeros(scale)=28
ASHIFT=31-28=3
N<<ASHIFT = N<<3 = N*2*2*2 = N*8 = N*scale
针对Object对象进行CAS操作。即是对应Java变量引用o,原子性地更新o中偏移地址为offset的属性的值为x,当且仅的偏移地址为offset的属性的当前值为expected才会更新成功返回true,否则返回false。
if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))) {
break;
}
当然,前提是针对f进行synchronize加锁。通过这段代码,我们可以看得出,ConcurrentHashMap是针对具体某个下标的Node进行并发竞争加锁的。极大的避免了由于加锁导致的效率低下的问题。
下面,我们就针对这3个part进行解析
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent) {
e.val = value;
}
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key, value, null);
break;
}
}
}
private final void tryPresize(int size) {
int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(size + (size >>> 1) + 1);
int sc;
while ((sc = sizeCtl) >= 0) {
Node<K,V>[] tab = table; int n;
if (tab == null || (n = tab.length) == 0) {
... ...
}
else if (c <= sc || n >= MAXIMUM_CAPACITY) {
break;
}
else if (tab == table) {
... ...
}
}
}
这块就是创建table数组,没什么别的复杂逻辑。
针对如上特殊情况,即直接break跳出循环。
if (tab == null || (n = tab.length) == 0) {
n = (sc > c) ? sc : c;
if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) { /** 将sizeCtl设置为-1 */
try {
if (table == tab) {
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = nt;
sc = n - (n >>> 2); /** 3/4*n */
}
} finally {
sizeCtl = sc; /** 将sizeCtl设置为3/4的table数组长度 */
}
}
}
else if (c <= sc || n >= MAXIMUM_CAPACITY) { /** 表越界 */
break;
}
else if (tab == table) {
int rs = resizeStamp(n);
if (sc < 0) {
Node<K,V>[] nt;
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || sc == rs + MAX_RESIZERS || (nt = nextTable) == null || transferIndex <= 0) {
break;
}
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
transfer(tab, nt);
}
}
else if (U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2)) { // sizeCtl=-2145714174
transfer(tab, null);
}
}
static final int resizeStamp(int n) {
return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
}
【解释】
其中,Integer.numberOfLeadingZeros(n)具体逻辑,请参考【5.3.8> numberOfLeadingZeros(int i)】
1> 假设n=16,那么二进制就是00010000,那么从左侧最高位开始计算,连续一共有27个0,那么Integer.numberOfLeadingZeros(16)就返回27。
2> RESIZE_STAMP_BITS=16,那么1<<(RESIZE_STAMP_BITS - 1)=1<<(16-1)=1<<15
3> 我们在计算27 | 15,转换为二进制就是:00011011 | 00001000000000000000 = 00001000000000011011
综上所述,resizeStamp返回的结构由三部分组成,就是:
【高16位】16个0
【第16位】1
【第0~15位】"以二进制对table数组长度进行转换,然后计算从最左边算起连续的“0”的总数量"的二进制表现。
if (sc < 0) {
Node<K,V>[] nt;
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || sc == rs + MAX_RESIZERS || (nt = nextTable) == null || transferIndex <= 0) {
break;
}
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
transfer(tab, nt);
}
}
因为在table被其他线程操作的时候,sc其实高16位表示的就是resizeStamp返回的值,即,我们可以认为是table数组长度的信息。那么如果不等于rs,说明数组的长度已经变化了,如果sc==rs+1,说明数组长度是二进制里前进了1个bit,即:十进制中原数组长度的2倍。后面其他的判断,就不一一说明了,比较容易理解。我们来关注else if中的内容,因为这部分的transfer方法,才是我们关注的重点。如下所示:
else if (U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2)) {
transfer(tab, null);
}
高16位:记录了旧数组的容量大小。
低16位:保存了参与扩容的线程数量,假设低16位是n,则n-1就是扩容的线程数。
问题:为什么要+2而不是从1开始计数呢?
答:因为数组初始化时,sizeCtl设置为-1,所以1的那个位置被占了,所以从2开始计算。
if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE) {
stride = MIN_TRANSFER_STRIDE;
}
if (nextTab == null) { // eg1: nextTab=null
try {
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1]; /** nt=2*n */
nextTab = nt; /** 由于nextTab为null,所以此处初始化一个nextTab */
} catch (Throwable ex) {
sizeCtl = Integer.MAX_VALUE;
return;
}
nextTable = nextTab;
transferIndex = n; /** 当出现并发扩容时,这个全局变量,是用来给各个线程分配节点的。*/
}
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; /** 下一个索引 */
int nextBound; /** 下一个边界 */
if (--i >= bound || finishing) { /** i执行-1操作,即:往前遍历一步 */
advance = false; /** 跳出while循环 */
}
else if ((nextIndex = transferIndex) <= 0) { /** 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; /** i表示需要遍历数组的下标,用于下面根据i来迁移对应的链表 */
advance = false; /** 因为advance=false,所以跳出while循环 */
}
}
... 下面代码后续我们在分析 ...
}
【解释】
所以,每个线程迁移数据的范围是从bound到i,迁移长度为stride。
if (i < 0 || i >= n || i + n >= nextn) {
... case1:扩容迁移结束逻辑 ...
}
else if ((f = tabAt(tab, i)) == null) {
... case2:如果下标i处没有节点,则不需要进行扩容迁移操作 ...
}
else if ((fh = f.hash) == MOVED) {
... case3:下标为i的这个位置已经被处理过了,设置advance = true,重新执行while(advance) ...
}
else {
... case4:执行扩容迁移操作 ...
}
【解释】
下面的c-1、c-2、c-3、c-4四步骤进行详细解析。
if (i < 0 || i >= n || i + n >= nextn) { /** 扩容的活儿都分配完毕了 */
int sc;
if (finishing) {
nextTable = null;
table = nextTab;
sizeCtl = (n << 1) - (n >>> 1); /** 设置新数组的阈值——sizeCtl=1.5*n=0.75*2n */
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
}
}
【解释】
sc和sizeCtl前面已经介绍过,它包含两部分含义:高16位表示数组长度信息,低16位表示参与扩容数据迁移的总线程数。
else if ((f = tabAt(tab, i)) == null) { /** 如果下标i处没有节点,则不需要进行扩容迁移操作 */
advance = casTabAt(tab, i, null, fwd);
}
【解释】
else if ((fh = f.hash) == MOVED) { /** 下标为i的这个位置已经被处理过了,设置advance = true,重新执行while(advance) */
advance = true; // already processed
}
【解释】
synchronized (f) {
if (tabAt(tab, i) == f) {
Node<K,V> ln; /** 低位的node元素 */
Node<K,V> hn; /** 高位的node元素 */
if (fh >= 0) {
int runBit = fh & n; /** runBit=0时,表明元素f在当前的位置不用移动;否则需要移动到新扩展的区域 */
Node<K,V> lastRun = f;
/** 遍历到链表的最后一个元素,跳出for循环 */
for (Node<K,V> p = f.next; p != null; p = p.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; p != lastRun; p = p.next) {
int ph = p.hash;
K pk = p.key;
V pv = p.val;
if ((ph & n) == 0) { /** 将存储在低位区的Node拼装成新的链表 */
ln = new Node<K,V>(ph, pk, pv, ln);
}
else { /** 将存储在高位区的Node拼装成新的链表 */
hn = new Node<K,V>(ph, pk, pv, hn);
}
}
setTabAt(nextTab, i, ln); /** 设置低位 */
setTabAt(nextTab, i + n, hn); /** 设置高位 */
setTabAt(tab, i, fwd);
advance = true;
}
else if (f instanceof TreeBin) {
... 红黑树处理逻辑(不涉及讲解部分) ...
}
}
}
【解释】
传入一个int类型数据,返回这个数据的二进制串中从最左边算起连续的“0”的总数量。因为int类型的数据长度为32所以高位不足的地方会以“0”填充。
public static int numberOfLeadingZeros(int i) {
if (i == 0)
return 32;
int n = 1;
/**
* 00 | 00 | 0000 | 0000 0000 | 0000 0000 0000 0000
* [30] [28] [24] [16]
*/
/** 【32~17】(高16位)是否都为0,如果都是0,那么n=17,i左移16位,实现对高16位的清空操作 */
if (i >>> 16 == 0) { // eg1: 0100>>>16=0000
n += 16; // eg1: n=1+16=17
i <<= 16; // eg1: i=0100<<16= 0100 0000 0000 0000 0000
}
/** 【16~9】是否都为0 */
if (i >>> 24 == 0) {
n += 8; // eg1: n=17+8=25
i <<= 8; // eg1: i=0100 0000 0000 0000 0000 << 8 = 0100 0000 0000 0000 0000 0000 0000
}
/** 【8~5】是否都为0 */
if (i >>> 28 == 0) {
n += 4; // eg1: n=25+4=29
i <<= 4; // eg1: i=0100 0000 0000 0000 0000 0000 0000 << 4 = 0100 0000 0000 0000 0000 0000 0000 0000
}
/** 【4~3】是否都为0 */
if (i >>> 30 == 0) {
n += 2;
i <<= 2;
}
n -= i >>> 31; // eg1: n=29-(0100 0000 0000 0000 0000 0000 0000 0000 >>> 31)=29-0=29
return n;
}
final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
Node<K,V>[] nextTab;
int sc;
if (tab != null && (f instanceof ForwardingNode) && (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
int rs = resizeStamp(tab.length);
while (nextTab == nextTable && table == tab && (sc = sizeCtl) < 0) {
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || sc == rs + MAX_RESIZERS || transferIndex <= 0) {
break;
}
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
transfer(tab, nextTab);
break;
}
}
return nextTab;
}
return table;
}
【解释】
private final void addCount(long x, int check) {
CounterCell[] as; long b, s;
if ((as = counterCells) != null || !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
... ...
}
if (check >= 0) {
... ...
}
}
【解释】
下面我们针对这两种case进行详细介绍。
if ((as = counterCells) != null || !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
CounterCell a;
long v;
int m;
boolean uncontended = true;
if (as == null ||
(m = as.length - 1) < 0 ||
(a = as[ThreadLocalRandom.getProbe() & m]) == null ||
!(uncontended = U.compareAndSwapLong(a,CELLVALUE, v = a.value, v + x))) { /** 使用CellValue来计数 */
fullAddCount(x, uncontended); /** 使用CounterCell来计数 */
return;
}
if (check <= 1) {
return;
}
/** 统计所有count值 */
s = sumCount();
}
【解释】
private final void fullAddCount(long x, boolean wasUncontended) {
int h;
if ((h = ThreadLocalRandom.getProbe()) == 0) {
... 初始化操作随机数生成器 ...
}
/**【开启无限循环】*/
for (;;) {
/**
* case1: counterCells不为空 且 数组里面有元素
*/
if ((as = counterCells) != null && (n = as.length) > 0) {
f ((a = as[(n - 1) & h]) == null) {
...如果随机数h待插入的下标位置没有元素,则插入CounterCell ...
}
else if (!wasUncontended) { /** 如果wasUncontended=false(表示当前线程CAS竞争失败),则将wasUncontended重置为true */
wasUncontended = true;
}
else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x)) { /** 尝试将a的value值加x */
break;
}
else if (counterCells != as || n >= NCPU) {
collide = false; // At max size or stale
}
else if (!collide) {
collide = true;
}
else if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
... 多线程之间设置CounterCell的value值时发生碰撞,那么扩展CounterCell的长度,以减少碰撞次数 ...
}
... ...
}
/**
* case2: cellsBusy为0且counterCells为空
*/
else if (cellsBusy == 0 && counterCells == as && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
... 创建一个长度为2的CounterCell数组,将x赋值进数组,跳出循环 ...
}
/**
* case3: 尝试修改baseCount的值
*/
else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x)) {
... 如果修改成功,则跳出循环 ...
break;
}
}
【解释】
下面我们来关注这两部分。
ThreadLocalRandom.getProbe():用来获得随机数
ThreadLocalRandom.localInit():初始化当前线程的探针哈希值
ThreadLocalRandom.advanceProbe(h):更改当前线程的探针哈希值
CounterCell[] as;
CounterCell a;
int n;
long v;
if ((as = counterCells) != null && (n = as.length) > 0) {
if ((a = as[(n - 1) & h]) == null) { /** 如果随机数h待插入的下标位置没有元素 */
if (cellsBusy == 0) { // Try to attach new Cell
CounterCell r = new CounterCell(x); // Optimistic create
/** 通过CAS将cellsBusy设置为1,来表示正在操作CounterCell;操作完毕后,将cellsBusy设置为0,其他线程可以继续操作 */
if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
boolean created = false;
try { // Recheck under lock
CounterCell[] rs;
int m;
int j;
if ((rs = counterCells) != null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) {
rs[j] = r; /** 在下标j处,插入新建的CounterCell r */
created = true;
}
} finally {
cellsBusy = 0;
}
if (created) {
break;
}
continue; // Slot is now non-empty
}
}
collide = false; /** collide:碰撞,cellsBusy不等于0时,表示有其他线程正在操作CounterCell,collide设置为false */
}
else if (!wasUncontended) { /** 如果wasUncontended=false(表示当前线程CAS竞争失败),则将wasUncontended重置为true */
wasUncontended = true; // CAS already known to fail,Continue after rehash
}
else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x)) { /** 尝试将a的value值加x */
break;
}
else if (counterCells != as || n >= NCPU) {
collide = false; // At max size or stale
}
else if (!collide) {
collide = true;
}
/** 多线程之间设置CounterCell的value值时发生碰撞,那么扩展CounterCell的长度,以减少碰撞次数 */
else if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
try {
if (counterCells == as) {// Expand table unless stale
CounterCell[] rs = new CounterCell[n << 1]; /** 根据原数组长度扩张2倍*/
for (int i = 0; i < n; ++i) {
rs[i] = as[i]; /** 进行数据迁移 */
}
counterCells = rs;
}
} finally {
cellsBusy = 0;
}
collide = false;
continue; // Retry with expanded table
}
/** 更改当前线程的探针哈希值 */
h = ThreadLocalRandom.advanceProbe(h);
}
Java8的@sun.misc.Contended注解(Contended:有争议的)
@sun.misc.Contended是Java8新增的一个注解,对某字段加上该注解则表示该字段会单独占用一个缓存行(Cache Line)。
这里的缓存行是指CPU缓存(L1、L2、L3)的存储单元,常见的缓存行大小为64字节。
(注:JVM添加-XX:-RestrictContended参数后@sun.misc.Contended注解才有效)
单独使用一个缓存行有什么作用?
答:避免伪共享
为了提高读取速度,每个CPU有自己的缓存,CPU读取数据后会存到自己的缓存里。而且为了节省空间,一个缓存行可能存储着多个变量,即伪共享。
但是这对于共享变量,会造成性能问题,如下所示:
当一个CPU要修改某共享变量A时会先锁定自己缓存里A所在的缓存行,并且把其他CPU缓存上相关的缓存行设置为无效。但如果被锁定或失效的缓存行里,还
存储了其他不相干的变量B,其他线程此时就访问不了B,或者由于缓存行失效需要重新从内存中读取加载到缓存里,这就造成了开销。所以让共享变量A单独
使用一个缓存行就不会影响到其他线程的访问。
Java8之前的方案是什么?
在Java8之前,是通过代码里手动添加属性的方式解决的,如:
class LongWithPadding {
long value;
long p0, p1, p2, p3, p4, p5, p6;
}
一个long占8个字节,再添加7个long属性就会变成64个字节,刚好是一个缓存行大小。
但是注意,Java7开始JVM做优化时可能会把不用的变量给去掉,所以这种方法并不推荐使用。
适用场景
主要适用于频繁写的共享数据上。如果不是频繁写的数据,那么CPU缓存行被锁的几率就不多,所以没必要使用了,否则不仅占空间还会浪费CPU访问操作数据的时间。
if ((a = as[(n - 1) & h]) == null) { /** 如果随机数h待插入的下标位置没有元素 */
if (cellsBusy == 0) { // Try to attach new Cell
CounterCell r = new CounterCell(x); // Optimistic create
/** 通过CAS将cellsBusy设置为1,来表示正在操作CounterCell;操作完毕后,将cellsBusy设置为0,其他线程可以继续操作 */
if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
boolean created = false;
try { // Recheck under lock
CounterCell[] rs;
int m;
int j;
if ((rs = counterCells) != null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) {
rs[j] = r; /** 在下标j处,插入新建的CounterCell r */
created = true;
}
} finally {
cellsBusy = 0;
}
if (created) {
break;
}
continue; // Slot is now non-empty
}
}
collide = false; /** collide:碰撞,cellsBusy不等于0时,表示有其他线程正在操作CounterCell,collide设置为false */
}
else if (!wasUncontended) {
wasUncontended = true; // CAS already known to fail,Continue after rehash
}
else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x)) {
break;
}
else if (counterCells != as || n >= NCPU) {
collide = false; // At max size or stale
}
else if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
try {
if (counterCells == as) {// Expand table unless stale
CounterCell[] rs = new CounterCell[n << 1]; /** 根据原数组长度扩张2倍*/
for (int i = 0; i < n; ++i) {
rs[i] = as[i]; /** 进行数据迁移 */
}
counterCells = rs;
}
} finally {
cellsBusy = 0;
}
collide = false;
continue; // Retry with expanded table
}
else if (cellsBusy == 0 && counterCells == as && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
boolean init = false;
try { // Initialize table
if (counterCells == as) {
CounterCell[] rs = new CounterCell[2]; /** 创建长度为2的数组 */
rs[h & 1] = new CounterCell(x);
counterCells = rs;
init = true;
}
} finally {
cellsBusy = 0;
}
if (init) {
break;
}
}
else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x)) {
break; // Fall back on using base
}
final long sumCount() {
CounterCell[] as = counterCells; CounterCell a;
long sum = baseCount;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null)
sum += a.value;
}
}
return sum;
}
【解释】
里面逻辑比较简单,ConcurrentHashMap里总的kv数量就是:【baseCount数量】+【sum(CounterCells里所有CounterCell的value)】
while (s >= (long)(sc = sizeCtl) && (tab = table) != null && (n = tab.length) < MAXIMUM_CAPACITY) {
int rs = resizeStamp(n);
if (sc < 0) {
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || /** sc右移16位,则读取的就是原高16位的内容,即:table容量相关信息;不等于rs说明table容量发生了不一致的情况 */
sc == rs + 1 ||
sc == rs + MAX_RESIZERS ||
(nt = nextTable) == null ||
transferIndex <= 0) {
break;
}
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) { /** 加入1个共同扩容的线程,即:sc+1*/
transfer(tab, nt);
}
}
/** 执行扩容操作 */
else if (U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2)) {
transfer(tab, null);
}
/** 统计所有count值 */
s = sumCount();
}
【解释】
逻辑包含两个内容:
case1:如果sc为负值,表明正在执行扩容操作中,那么也加入扩容的“大部队”中
case2:否则,表明table数组没有扩容,那么,发起扩容操作。