Я читал, что в параллельном хэшмапе на Java возможны одновременные вставки, поскольку он разделен на сегменты, и для каждого сегмента выполняется отдельная блокировка. Но если две вставки будут происходить на одном и том же сегменте, то этих одновременных действий не произойдет. Вопрос в том, что произойдет в таком случае? Будет ли вторая вставка ждать до первого завершения или что?Параллельная установка hashmap Одновременная вставка
ответ
В общем, вы не должны быть слишком озабочены, как ConcurrentHashMap
реализуется. Он просто соответствует контракту ConcurrentMap
, который гарантирует, что возможны одновременные изменения.
Но ответ на ваш вопрос: да, одна вставка может дождаться завершения другого. Внутри он использует блокировки, которые гарантируют, что один поток ожидает, пока другой не выпустит блокировку. Класс Segment
, используемый внутренне, фактически наследует от ReentrantLock
. Вот сокращенный вариант Segmenet.put()
:
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
HashEntry<K,V> node = tryLock() ? null : scanAndLockForPut(key, hash, value);
V oldValue;
try {
// modifications
} finally {
unlock();
}
return oldValue;
}
private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
// ...
int retries = -1; // negative while locating node
while (!tryLock()) {
if (retries < 0) {
// ...
}
else if (++retries > MAX_SCAN_RETRIES) {
lock();
break;
}
else if ((retries & 1) == 0 && (f = entryForHash(this, hash)) != first) {
e = first = f; // re-traverse if entry changed
retries = -1;
}
}
return node;
}
Это может дать вам идею.
Посмотрите на javadoc for ConcurrentMap. В нем описаны дополнительные методы, доступные для борьбы с одновременными мутациями карты.
Если 2 обновления пытаются произойти в одном сегменте, они будут вступать в противоречие друг с другом, и один из них должен будет ждать. Вы можете оптимизировать это, выбирая значение concurrencyLevel, которое учитывает количество потоков, которые будут одновременно обновлять хэш-карту.
Вы можете найти все детали в javadoc for the class
Эвристика с большинством параллельных структур данных состоит в том, что сначала создается модифицированная структура данных, которая имеет переднюю структуру данных, видимую внешним методам. Затем, когда модификация завершена, структура данных резервного копирования создается публичной структурой данных, а структура общедоступных данных выталкивается обратно. Для этого есть что-то большее, но это типичный контракт.
Спасибо ... но эта концепция структуры данных базы данных здесь для меня нова ... Не могли бы вы предоставить мне ссылку, где я могу прочитать об этом подробно? –
В документации указано, что * операции поиска * не блокируются. Когда вы начинаете изменять, вы не можете обойтись без блокировок. – Mifeet
ConcurrentHashMap содержит массив сегментов, который, в свою очередь, содержит массив HashEntry. Каждый HashEntry содержит ключ, значение и указатель на следующую соседнюю запись.
Но он приобретает замок в сегменте. Следовательно, вы правы. то есть вторая вставка ждет, пока первый не будет завершен.
Вы читали Javadocs для 'ConcurrentHashMap'? – Kayaman
q1) он все еще работает, q2) да, второй должен ждать. Вы можете увеличить количество сегментов, если хотите уменьшить вероятность этого, но вам очень редко нужно. –
@ Кайаман - Прочитайте javadocs, но не нашел ничего, связанного с моим вопросом. –