Блокировки чтения и записи ConcurrentHashMap

Я пытаюсь найти ответ на них, но не могу найти его в Google или в документах Java.

Случай 1: в ConcurrentHashMap, предположим, что поток t1 считывается из сегмента n, и один и тот же поток t2 хочет записать на том же сегменте n:

Вопрос 1: будут ли эти две операции выполняться один за другим или они будут выполняться одновременно?


Случай 2: в ConcurrentHashMap, предположим, что поток t1 записывает на сегмент n, и один и тот же поток t2 хочет читать из того же сегмента n,

Вопрос 2: будут ли эти две операции выполняться один за другим или они будут выполняться одновременно?

Ответ 1

Я думаю, что javadoc отвечает на ваши вопросы:

Операции поиска (включая get) обычно не блокируются, поэтому могут перекрываются с операциями обновления (включая put и remove). извлечения отражают результаты последних завершенных операций обновления удерживая их наступление. Для совокупных операций, таких как putAll и четкие, одновременные изъятия могут отражать вставку или удаление только некоторые записи.

Сегменты для операций обновления:

Разрешенный concurrency среди операций обновления управляется необязательный аргумент конструктора concurrencyLevel (по умолчанию 16), который используется как подсказка для внутренней калибровки.

Итак, короче говоря, чтение не блокируется (оно реализуется как чтение изменчивых переменных). Записи могут блокировать друг друга, если они пишут в том же сегменте.

Ответ 2

В соответствии с документами ConcurrentHashMap Oracle

Конструктор ConcurrentHashMap выглядит следующим образом:

public ConcurrentHashMap (int initialCapacity, float loadFactor, int concurrencyLevel)

Таким образом, вышеприведенная строка создает новую пустую карту с указанной начальной мощностью, коэффициентом загрузки и уровнем concurrency. где, Важные параметры для рассмотрения из ConcurrentHashMap Constructor:

  • initialCapacity - начальная емкость. Выполнение выполняется внутренняя калибровка для размещения этого множества элементов.
  • concurrencyLevel - оценочное число одновременных обновлений потоков. реализация выполняет внутренний размер, чтобы попытаться много потоков.

В ConcurrentHashMap Api вы найдете следующие константы.

  • static final int DEFAULT_INITIAL_CAPACITY = 16;
  • static final int DEFAULT_CONCURRENCY_LEVEL = 16;

параметр начальной емкости и concurrency параметров уровня ConcurrentHashMap-конструктора (или объекта) по умолчанию установлены 16.

Таким образом, вместо блокировки по карте, ConcurrentHashMap по умолчанию сохраняет список из 16 блокировок (количество блокировок, равное начальной емкости, по умолчанию 16), каждая из которых используется для блокировки на одном ведре Map.This указывает, что 16 потоков (количество потоков, равных уровню concurrency, которое по умолчанию 16) может изменять коллекцию в одно и то же время, учитывая, каждый поток работает в разных ведрах. Поэтому, в отличие от хэш-таблицы, мы выполняем любую операцию (обновление, удаление, чтение, создание) без блокировки всей карты в ConcurrentHashMap.

Операции поиска (включая get) обычно не блокируются. В этом случае он использует концепцию volatile., поэтому может перекрываться с операциями обновления (включая put и remove). Retrievals отражают результаты последних завершенных операций по обновлению с их началом.

Допустимый concurrency среди операций обновления управляется необязательным аргументом конструктора concurrencyLevel (по умолчанию 16), который используется как подсказка для внутреннего размера. Таблица внутренне разделена, чтобы попытаться разрешить указанное количество одновременных обновлений без конкуренции. Поскольку размещение в хэш-таблицах по существу является случайным, фактический concurrency будет отличаться. В идеале вы должны выбрать значение для размещения столько потоков, сколько когда-либо одновременно измените таблицу. Использование значительно более высокой ценности, чем вам нужно, может потерять пространство и время, а значительно меньшее значение может привести к конфликту с потоком.

Надеюсь, это поможет!