关于java:看看不一样的ConcurrentHashMap

38次阅读

共计 2660 个字符,预计需要花费 7 分钟才能阅读完成。

构造函数
先来看看几个重要的参数:

/**
 * 默认初始容量,在没有在构造函数中另外指定时应用
 */
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<K,V>[] segments;

下面的参数晓得大略就行,在接下来的代码中就能了解这些参数的作用的,接下来看看构造方法:

/**
 * 应用指定的初始容量,负载因子和并发级别创立一个新的空映射。*
 * @param 初始容量。该实现执行外部大小调整以包容许多元素。* 
 * @param loadFactor  [Skrill 下载](https://www.gendan5.com/wallet/Skrill.html)负载系数阈值,用于管制调整大小。* 当每个仓的均匀元素数超过此阈值时,能够执行大小调整。* 
 * @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<K,V> s0 = new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
                         (HashEntry<K,V>[])new HashEntry[cap]);
    Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
    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);
}

正文完
 0