问题:
我们在创建ConcurrentHashMap对象的时候通常直接new ConcurrentHashMap();,此时底层默认初始容量为16。那么如果手动设置初始容量new ConcurrentHashMap(int initialCapacity);会发生什么呢?请看下面分析:
几个用到的变量值转换:
@Native public static final int MAX_VALUE = 0x7fffffff = 2^31 - 1
static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 = 2^31 - 1 - 2^3 = 2 ^ 28 - 1
//32位hash 最高2位勇于控制
private static final int MAXIMUM_CAPACITY = 1 << 30 = 1 << 30 = 2 ^ 0 << 30 = 2 ^ 30
底层方法实现:
//初始化时设置初始容量
//设置initialCapacity = 9 (2 ^ 3 + 1)
public ConcurrentHashMap(int initialCapacity) {
if (initialCapacity < 0)
throw new IllegalArgumentException();
//32位hash 最高2位勇于控制
//MAXIMUM_CAPACITY = 1 << 30 = 2 ^ 0 << 30 = 2 ^ 30
//如果大于则cap = 2 ^ 31
int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
MAXIMUM_CAPACITY :
tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); // 14
this.sizeCtl = cap;
}
//c = 14
private static final int tableSizeFor(int c) {
int n = c - 1; //n = 13
n |= n >>> 1; //n = 13 | 6 = 1101 | 0110 = 1111 = 15
n |= n >>> 2; //n = 15 | 3 = 1111 | 0011 = 1111 = 15
n |= n >>> 4; //n = 15 | 0 = 1111 | 0000 = 1111 = 15
n |= n >>> 8; //n = 15
n |= n >>> 16; //n = 15
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; //返回16
}
测试几个值:
//1. 测试设置initialCapacity = 7
tableSizeFor(11);
int n = 11 - 1 = 10
n = 10 | 10 >>> 1 = 1010 | 0101 = 1111 = 15
n = 15 | 15 >>> 2 = 1111 | 0011 = 1111 = 15
n = 15
return 15 + 1 = 16;
//2. 测试设置initialCapacity = 17
tableSizeFor(26);
int n = 26 - 1 = 25
n = 25 | 25 >>> 1 = 11001 | 01100 = 11101 = 29
n = 29 | 29 >>> 2 = 11001 | 00111 = 11111 = 31
n = 31
return 31 + 1 = 32;
//3. 测试设置initialCapacity = 3
tableSizeFor(5);
n = 5 | 5 >>> 1 = 0101 | 0010 = 0111 = 7
n = 7 | 7 >>> 2 = 0111 | 0001 = 0111 = 7
n = 7
return 7 + 1 = 8;
//4. 测试设置initialCapacity = 2
tableSizeFor(4)
int n = 4 - 1 = 3
n = 3 | 3 >>> 1 = 11 | 01 = 11 = 3
n = 3
return 3 + 1 = 4
//5. 测试设置initialCapacity = 4
tableSizeFor(7)
int n = 7 - 1 = 6
n = 6 | 6 >>> 1 = 110 | 011 = 111 = 7
n = 3
return 7 + 1 = 8
//6. 测试设置initalCapacity = 8
tableSizeFor(13)
int n = 13 - 1 = 12
n = 12 | 12 >>> 1 = 1100 | 0110 = 1110 = 14
n = 14 | 14 >>> 1 = 1110 | 0111 = 1111 = 15
n = 15
return 15 + 1 = 16
产生的现象:
//2 --> 4
//3 --> 8 特殊现象:3 * 2 = 6距离4和8相等,选择向后转换为8
//4 --> 8
//7 --> 16
//8 --> 16
//9 --> 16
//17 --> 32
结论:
ConcurrentHashMap初始化设置容量时底层会自动转换为距设置值2倍最近的2的次幂;当前后距离相等时,会选择向后转换。