分类: Java
2021-05-26 17:00:20
构造函数
先来看看几个重要的参数:
/**
* 默认初始容量,在没有在构造函数中另外指定时使用
*/
static final int DEFAULT_INITIAL_CAPACITY = 16;
/**
* 默认加载因子,在没有在构造函数中另外指定时使用
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 默认并发级别,在没有在构造函数中另外指定时使用。
*/
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
/**
* 最大容量,如果两个构造函数都使用参数隐式指定了更高的值,则使用该容量。
* 必须是2的幂且小于等于 1 << 30,以确保条目可以使用int进行索引
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 每段表的最小容量。必须为2的幂,至少为2的幂,以免在延迟构造后立即调整下次使用时的大小。
*/
static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
/**
* 允许的最大段数;用于绑定构造函数参数。必须是小于1 << 24的2的幂。
*/
static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
/**
* 在锁定整个表之前,size和containsValue()方法的不同步重试次数。
* 如果表进行连续修改,这将用于避免无限制的重试,这将导致无法获得准确的结果。
*/
static final int RETRIES_BEFORE_LOCK = 2;
/**
* 用于编入段的掩码值。密钥的哈希码的高位用于选择段。
*/
final int segmentMask;
/**
* 段内索引的移位值。
*/
final int segmentShift;
/**
* 段,每个段都是一个专用的哈希表
*/
final Segment
上面的参数知道大概就行,在接下来的代码中就能理解这些参数的作用的,接下来看看构造方法:
/**
* 使用指定的初始容量,负载因子和并发级别创建一个新的空映射。
*
* @param 初始容量。该实现执行内部大小调整以容纳许多元素。
*
* @param loadFactor 负载系数阈值,用于控制调整大小。
* 当每个仓的平均元素数超过此阈值时,可以执行大小调整。
*
* @param concurrencyLevel 估计的并发更新线程数。该实现执行内部大小调整以尝试容纳这么多线程。
*
* @throws IllegalArgumentException 如果初始容量为负,或者负载因子或concurrencyLevel为非正数。
*/
@SuppressWarnings("unchecked")
public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
//对非法输入进行处理
if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
throw new IllegalArgumentException();
// 若并发线程数大于最大段数,则等于最大段数
if (concurrencyLevel > MAX_SEGMENTS)
concurrencyLevel = MAX_SEGMENTS;
// 为保证能通过位与运算的散列算法来定位segments数组索引,要保证数组长度为2的幂,查找最适合参数的二乘幂
int sshift = 0;
int ssize = 1;
while (ssize < concurrencyLevel) {
++sshift;
ssize <<= 1;
}
this.segmentShift = 32 - sshift;
this.segmentMask = ssize - 1;
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
//初始化每个segment中的HashEntry长度
int c = initialCapacity / ssize;
//如果c大于1,货币代码cap会取大于等于c的2次方,所以cap要么等于1要么等于2的幂次方
if (c * ssize < initialCapacity)
++c;
int cap = MIN_SEGMENT_TABLE_CAPACITY;
while (cap < c)
cap <<= 1;
// 创建segments数组,并初始化segments[0]
Segment
(HashEntry
Segment
UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
this.segments = ss;
}
public ConcurrentHashMap(int initialCapacity, float loadFactor) {
this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
}
public ConcurrentHashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
}
public ConcurrentHashMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
}
public ConcurrentHashMap(Map extends K, ? extends V> m) {
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
putAll(m);
}