Возможно ли иметь более 32 блокировок в ConcurrentHashMap

Я читал, что ConcurrentHashMap лучше работает в многопоточности, чем Hashtable, из-за блокировки на уровне корзины, а не блокировки всей карты. На карту можно установить не более 32 замков. Хотите знать, почему 32 и почему не более 32 замков.


person DKSRathore    schedule 22.11.2009    source источник
comment
В моем ответе есть ссылка на исходный код. Вы можете прочитать это, чтобы доказать себе, что максимум на самом деле больше 32 (это 2 ^ 16 или 65 536, как заметил Маллер).   -  person John Feminella    schedule 22.11.2009


Ответы (4)


Если вы говорите о Java ConcurrentHashMap, то ограничение составляет произвольный:

Создает новую карту с теми же сопоставлениями, что и данная карта. Карта создается с емкостью, в 1,5 раза превышающей количество сопоставлений в данной карте или 16 (в зависимости от того, что больше), с коэффициентом загрузки по умолчанию (0,75) и уровнем параллелизма (16).

Если вы прочитаете исходный код, станет ясно что максимальное количество сегментов составляет 2 ^ 16, чего должно быть более чем достаточно для любых мыслимых потребностей в ближайшем будущем.

Возможно, вы думали о некоторых альтернативных экспериментальных реализациях, таких как этот:

Этот класс поддерживает жестко заданный уровень параллелизма 32. Это позволяет одновременно выполнять до 32 операций размещения и/или удаления.

Обратите внимание, что, как правило, факторы, отличные от эффективности синхронизации, обычно являются узкими местами, когда более 32 потоков пытаются обновить один ConcurrentHashMap.

person John Feminella    schedule 22.11.2009
comment
Ницца. Большое спасибо, Джон. Этот вопрос мучил меня с недели. - person DKSRathore; 22.11.2009
comment
@John, это предел максимального количества читателей/писателей/читателей+писателей? - person Geek; 04.09.2012

По умолчанию не 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.
person cletus    schedule 22.11.2009
comment
Да, по умолчанию 16, но максимально разрешено 32. И я хочу знать, почему 32. - person DKSRathore; 22.11.2009
comment
Я не знаю, откуда вы взяли 32. Я смотрю на источник (Java 6) и нигде не упоминается 32. - person cletus; 22.11.2009
comment
Эта статья датирована 21 августа 2003 г., то есть предшествует даже Java 5 и поэтому была скорее предварительным просмотром, чем чем-либо еще. Всегда рассматривайте такую ​​информацию в контексте ее даты. Если вы сомневаетесь, перейдите к источнику JDK. - person cletus; 22.11.2009
comment
@cletus Я уже некоторое время ломаю голову над вопросом, я огляделся, но не смог найти ответ. Я хочу знать, что произойдет, если concurrencyLevel будет больше, чем capacity карты. Таким образом, по умолчанию оба равны 16, что означает, что каждое ведро будет иметь блокировку. А если ёмкость будет 32 а concurrencyLevel 16 то блокировка будет держаться на 2 ведра. Но что происходит, когда concurrencyLevel равно 32, а емкость равна 16? - person rd22; 10.09.2016
comment
будут ли держаться 2 замка на одном и том же ведре? - 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;
person mhaller    schedule 22.11.2009
comment
В порядке. Я пропустил это в java src. Спасибо, Майк. - person DKSRathore; 22.11.2009

Чтобы использовать все уровни параллелизма по умолчанию, равные 16, вам необходимо иметь 16 ядер, одновременно использующих карту. Если у вас 32 ядра используют карту только 25% времени, то одновременно будут использоваться только 8 из 16 сегментов.

Таким образом, вам нужно иметь много ядер, использующих одну и ту же карту и не делающих ничего особенного. Реальные программы обычно делают что-то другое, кроме доступа к одной карте.

person Peter Lawrey    schedule 29.11.2009
comment
Питер, не могли бы вы указать мне какую-нибудь подробную ссылку или ссылку на такие детали. - person DKSRathore; 29.11.2009
comment
Это просто логично, как я это вижу. Количество ядер/гиперпотоков, которые у вас есть, определяет количество активных потоков, которые вы можете иметь; назовите его A. Если потоки тратят процент своего времени на карте, назовите его P. Предполагается, что вам нужно около A * P сегментов (возможно, больше, чтобы уменьшить конкуренцию). Итак, если у вас 4 ядра, и он тратит 25% время на карте (это было бы очень много для программы, которая выполняет полезную работу), вам нужно около 4 сегментов по 25%, т.е. 1. Вы можете выполнить математику. для вашего количества ядер и процента времени, которое вы ожидаете от использования карты. - person Peter Lawrey; 30.11.2009
comment
попадание в кеш-промах выручит текущий поток/ядро для чего-то другого, это не так просто. - person bestsss; 24.01.2011
comment
Промахи кеша случаются очень часто, я не верю, что это приводит к переключению контекста. Что вы подразумеваете под отказом от текущего потока/ядра к чему-то другому? - person Peter Lawrey; 24.01.2011
comment
@PeterLawrey ограничивает ли это максимальное количество потоков чтения / максимальное количество потоков записи / максимальное количество потоков (чтение + запись)? - person Geek; 04.09.2012