Как ConcurrentHashMap обрабатывает переименование?

Мне интересно, как ConcurrentHashMap обрабатывает повторную запись, пока другой поток все еще записывается на другой сегмент/раздел. Насколько я понимаю, ConcurrentHashMap блокирует сегмент независимо, так, например, Thread1 записывает сегмент1 немного раньше, чем Thread2 записывает в сегмент2, и что произойдет, если требуется, чтобы таблица изменяла размер и переименовывалась после вставки Thread1, но Thread2 находится в середине операции записи? он блокирует всю карту для переигрывания? и есть ли у него что-то вроде tell Thread2, чтобы остановиться и дождаться, пока переигрыш не будет завершен? потому что Thread2 может иметь шанс закончить запись сегмента 1 после изменения размера таблицы, правильно?

Ответы

Ответ 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];
}

Итак, если вы вызываете put, он сначала определяет Segment, используя segmentFor, а затем нажимает на это Segment

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

В ConcurrentHashMap массив таблиц создается для каждого сегмента. И массив сегментов, созданный на основе concurrencyLevel.

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

Таким образом, REHASHING также будет выполняться для каждой таблицы сегментов. Таким образом, это не повлияет на таблицу другого сегмента.

Это что-то вроде массива {Сегменты} массива {элементов} (2D). Так очень быстро:)