tryPreSize是ConcurrentHashMap扩容方法之一
private final void tryPresize(int size) {
//如果大小为MAXIMUM_CAPACITY最大总量的一半,那么直接扩容为MAXIMUM_CAPACITY,否则计算最小幂次方
int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
tableSizeFor(size + (size >>> 1) + 1);
int sc;
//如果sizeCtl为正数或0
while ((sc = sizeCtl) >= 0) {
Node<K,V>[] tab = table; int n;
//如果table还未进行初始化
if (tab == null || (n = tab.length) == 0) {
n = (sc > c) ? sc : c;
//cas修改sizeCtl为-1,表示table正在进行初始化
if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
//确认其他线程没有对table修改
if (table == tab) {
@SuppressWarnings("unchecked")
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = nt;
//0.75*n
sc = n - (n >>> 2);
}
} finally {
sizeCtl = sc;
}
}
}
//如果扩容大小没有达到阈值,或者超过最大容量
else if (c <= sc || n >= MAXIMUM_CAPACITY)
break;
else if (tab == table) {
/**生成表的生成戳,每个n都有不同的生成戳
* static final int resizeStamp(int n) {
* return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
* }
* Integer.numberOfLeadingZeros(n)在指定 int 值的二进制补码表示形式中最高位(最左边)的 1 位之前,返回零位的数量
* 例如 n为16 0001 0000 则Integer.numberOfLeadingZeros(n)为27,因为n为2的幂次方,因此不同的n此结果也不同
* 然后与(1 << (RESIZE_STAMP_BITS - 1)) | ,相当于2^15 | n中0的个数。
* (因此其左移16位后符号位为1,结果肯定是个负数)
*/
int rs = resizeStamp(n);
if (sc < 0) {
Node<K,V>[] nt;
/**1.第一个判断 sc右移RESIZE_STAMP_SHIFT位,也就是比较高ESIZE_STAMP_BITS位生成戳和rs是否相等
* 相等则代表是同一个n,是在同一容量下进行的扩容,
* 2.第二个和第三个判断 判断当前帮助扩容线程数是否已达到MAX_RESIZERS最大扩容线程数
* 3.第四个和第五个判断 为了确保transfer()方法初始化完毕
*/
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);
}
/**如果没有线程在进行扩容,那么cas修改sizeCtl值,作为扩容的发起,rs左移RESIZE_STAMP_SHIFT位+2
* 上面说了,左移RESIZE_STAMP_SHIFT位,肯定是个负数,代表有一个线程正在进行扩容
* 此时sizeCtl高RESIZE_STAMP_BITS位为生成戳,低RESIZE_STAMP_SHIFT位为扩容线程数
*/
else if (U.compareAndSwapInt(this, SIZECTL, sc,
(rs << RESIZE_STAMP_SHIFT) + 2))
transfer(tab, null);
}
}
}
如有不足欢迎指正