Я читал, что ConcurrentHashMap лучше работает в многопоточности, чем Hashtable, из-за блокировки на уровне корзины, а не блокировки всей карты. На карту можно установить не более 32 замков. Хотите знать, почему 32 и почему не более 32 замков.
Возможно ли иметь более 32 блокировок в ConcurrentHashMap
Ответы (4)
Если вы говорите о Java ConcurrentHashMap
, то ограничение составляет произвольный:
Создает новую карту с теми же сопоставлениями, что и данная карта. Карта создается с емкостью, в 1,5 раза превышающей количество сопоставлений в данной карте или 16 (в зависимости от того, что больше), с коэффициентом загрузки по умолчанию (0,75) и уровнем параллелизма (16).
Если вы прочитаете исходный код, станет ясно что максимальное количество сегментов составляет 2 ^ 16, чего должно быть более чем достаточно для любых мыслимых потребностей в ближайшем будущем.
Возможно, вы думали о некоторых альтернативных экспериментальных реализациях, таких как этот:
Этот класс поддерживает жестко заданный уровень параллелизма 32. Это позволяет одновременно выполнять до 32 операций размещения и/или удаления.
Обратите внимание, что, как правило, факторы, отличные от эффективности синхронизации, обычно являются узкими местами, когда более 32 потоков пытаются обновить один ConcurrentHashMap
.
По умолчанию не 32, а 16. И вы можете переопределить его с помощью аргумент конструктора concurrency level
:
public ConcurrentHashMap(int initialCapacity,
float loadFactor,
int concurrencyLevel)
поэтому вы можете сделать:
Map<String, String> map = new ConcurrentHashmap<String, String)(128, 0.75f, 64);
чтобы изменить его на 64. По умолчанию (начиная с Java 6u17):
initialCapacity
: 16;loadFactory
: 0.75f;concurrencyLevel
: 16.
concurrencyLevel
будет больше, чем capacity
карты. Таким образом, по умолчанию оба равны 16, что означает, что каждое ведро будет иметь блокировку. А если ёмкость будет 32 а concurrencyLevel
16 то блокировка будет держаться на 2 ведра. Но что происходит, когда concurrencyLevel
равно 32, а емкость равна 16?
- person rd22; 10.09.2016
Согласно источнику ConcurrentHashMap
, максимально допустимым является 65536
:
/**
* The maximum number of segments to allow; used to bound
* constructor arguments.
*/
static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
public ConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel) {
if (concurrencyLevel > MAX_SEGMENTS)
concurrencyLevel = MAX_SEGMENTS;
Чтобы использовать все уровни параллелизма по умолчанию, равные 16, вам необходимо иметь 16 ядер, одновременно использующих карту. Если у вас 32 ядра используют карту только 25% времени, то одновременно будут использоваться только 8 из 16 сегментов.
Таким образом, вам нужно иметь много ядер, использующих одну и ту же карту и не делающих ничего особенного. Реальные программы обычно делают что-то другое, кроме доступа к одной карте.