ConcurrentHashMap如何处理重新哈希?

我想知道ConcurrentHashMap如何处理重新哈希,而另一个线程仍在另一个段/分区上写入。据我所知,ConcurrentHashMap 独立锁定段,例如,Thread1 在 Thread2 写入 segment2 之前写入段 1,如果它要求表在 Thread1 插入后调整大小和重新哈希,但 Thread2 处于写入操作的中间,会发生什么情况?它是否锁定了整个地图以进行重新哈希处理?它是否有类似告诉Thread2停止并等待重新哈希完成之类的东西?因为 Thread2 可能有机会在表调整大小后最终写入 segment1,对吗?


答案 1

每个段都单独重述,因此不会发生冲突。

ConcurrentHashMap是专用哈希表的数组,称为Segments

从源代码

final Segment<K,V>[] segments;

/**
 * Segments are specialized versions of hash tables.  This
 * subclasses from ReentrantLock opportunistically, just to
 * simplify some locking and avoid separate construction.
 */

如果您检查返回分段的方法

final Segment<K,V> segmentFor(int hash) {
    return segments[(hash >>> segmentShift) & segmentMask];
}

所以如果你叫它先确定用途,然后再叫放上去putSegmentsegmentForSegment

put源代码

public V put(K key, V value) {
    if (value == null)
        throw new NullPointerException();
    int hash = hash(key.hashCode());
    return segmentFor(hash).put(key, hash, value, false);
}

答案 2

在表中,为每个段创建数组。以及基于 创建的分段数组。ConcurrentHashMapconcurrencyLevel

    /**
     * The per-segment table. Elements are accessed via
     * entryAt/setEntryAt providing volatile semantics.
     */
    transient volatile HashEntry<K,V>[] table;

因此,重新哈希也将按段的表完成。因此,这不会影响另一个段的表。

这类似于 Array{Elements} (2D) 的 Array{Segments}。所以非常快:)