Как 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). Так очень быстро:)