返回

ConcurrentHashMap扩容利器:详解transfer方法

后端

好的,以下是关于 ConcurrentHashMap(JDK1.8)的扩容方法 transfer 的源码分析的文章:

ConcurrentHashMap 的扩容

在 ConcurrentHashMap 中,当哈希表的大小达到或超过某个阈值时,就会触发扩容操作。扩容是指将哈希表的大小加倍,并重新计算每个键的哈希值,以便将键均匀地分布到新的哈希表中。

transfer 方法的源码分析

transfer 方法是 ConcurrentHashMap 中负责扩容操作的核心方法。其源码如下:

final void transfer(TableEntry[] tab, int newCapacity) {
    int stride;
    if ((stride = ((newCapacity >>> 3) / NCPU) > 8) ?
        ((newCapacity >>> 3) / NCPU) : (NCPU)) < 8)
        stride = 8;   // if large enough, stride at least 8
    for (TableEntry e = tabAt(tab, stride, 0); e != null; ) {
        // skip bins with just null marker nodes
        TableEntry next = e.next;
        if (e.value == null && e.next == null)
            e = next;
        else if (e.next != null || e.hash == MOVED)
            transferStriped(e, next);
        else // single node on list
            transferKey(e, next);
        e = next;
    }
}

transfer 方法的工作原理

transfer 方法首先计算了一个 stride 值,该值用于确定要遍历的哈希表桶的数量。stride 值的计算公式为:

stride = ((newCapacity >>> 3) / NCPU) > 8 ? ((newCapacity >>> 3) / NCPU) : (NCPU)

其中,newCapacity 是新的哈希表容量,NCPU 是 CPU 的核数。stride 值的最小值为 8,最大值为 NCPU。

接下来,transfer 方法遍历哈希表,并对每个哈希表桶中的元素进行处理。如果一个哈希表桶中只有一个元素,则直接将该元素转移到新的哈希表中。如果一个哈希表桶中有多个元素,则将这些元素逐个转移到新的哈希表中。

在转移元素时,transfer 方法会使用 compareAndSet 方法来保证操作的原子性。compareAndSet 方法可以保证,如果某个元素在内存中的值没有发生改变,则该元素的值可以被修改。否则,compareAndSet 方法会返回 false,并且该元素的值不会被修改。

transfer 方法的性能优化

transfer 方法在设计时考虑到了性能优化。首先,transfer 方法采用了 stride 的方式来遍历哈希表,这可以减少遍历的哈希表桶的数量,从而提高性能。其次,transfer 方法使用了 compareAndSet 方法来保证操作的原子性,这可以减少锁的竞争,从而提高性能。

总结

ConcurrentHashMap 的 transfer 方法是扩容操作的核心方法。该方法能够在并发场景下安全地扩充哈希表的大小,从而提高 ConcurrentHashMap 的性能。transfer 方法的设计考虑到了性能优化,采用了 stride 的方式来遍历哈希表,并使用了 compareAndSet 方法来保证操作的原子性。