Является ли ConcurrentHashMap.putAll() атомарным?

Является ли метод ConcurrentHashMap.putAll(Map) атомарным?

Я не могу найти его в документации, и он не упоминается в интерфейсе ConcurrentMap, поэтому я думаю, что ответ отрицательный. Я прошу это быть уверенным, так как это не имело бы смысла, если бы эта операция не была атомарной, если честно.

Если он не атомарный, как лучше всего поддерживать атомарные вставки нескольких элементов? Вернуться к старой доброй синхронизации?


person Japer D.    schedule 14.12.2011    source источник


Ответы (4)


Это не атомарно, нет. Согласно документации класса:

Для агрегатных операций, таких как putAll и clear, одновременные выборки могут отражать вставку или удаление только некоторых записей.

Чтобы атомизировать его, вам придется использовать synchronized, да. Нет неблокирующего способа сделать это.

person ruakh    schedule 14.12.2011
comment
Как насчет другой (нестандартной) параллельной реализации Map? - person ; 15.12.2011
comment
@pst Кто может быть кандидатом? - person Japer D.; 15.12.2011
comment
@ДжаперД. Я понятия не имею. Просто интересно, есть ли у вас какое-то понимание, хотя этот ответ по-прежнему неполный. - person ; 15.12.2011
comment
@pst: Это хороший вопрос. Не зная точного использования, но в целом я предполагаю, что это было бы контрпродуктивно. ConcurrentHashMap можно назвать вероятностно-параллельным: он не является полностью неблокирующим, но работает за счет внутреннего разделения на фиксированное число сегментов (по умолчанию 16, но устанавливается в конструкторе) в надежде, что при записи нескольких разных потоков в карту одновременно, они вероятно будут записывать в записи, находящиеся в разных сегментах. Если они пишут в один и тот же сегмент, возможна некоторая блокировка. (продолжение) - person ruakh; 15.12.2011
comment
(продолжение) Чтобы putAll был атомарным, вам нужно полностью избавиться от этого (поскольку вы не можете атомарно сообщать об обновлении нескольких сегментов). Тем не менее, это зависит от вашего распределения операций. Если вы ожидаете, что нормальные put будут встречаться относительно редко, но ожидаете, что будет много get и putAll, то может иметь смысл создать подкласс HashMap, который использует ReadWriteLock для управления доступом: все операции чтения будут заключены в блокировку чтения, и все записи, включая весь putAll, будут завернуты в блокировку записи. - person ruakh; 15.12.2011
comment
Спасибо за информацию. Я создаю механизм транзакций. Таким образом, все измененные объекты должны быть видны сразу после фиксации транзакции. Вот почему я хотел, чтобы putAll был атомарным. - person Japer D.; 15.12.2011
comment
@JaperD.: В этом случае ReadWriteLock вполне может подойти. (Хотя, вопреки моему приведенному выше предложению расширить HashMap, вероятно, имеет смысл создать для него оболочку, которая реализует только те методы, которые вам нужны; has-a, а не is-a. В противном случае вам придется переопределять каждый метод. ) - person ruakh; 15.12.2011

вверху документа

Для агрегатных операций, таких как putAll и clear, одновременные выборки могут отражать вставку или удаление только некоторых записей.

person ratchet freak    schedule 14.12.2011

putAll() не является атомарным, а просто гарантирует, что каждый отдельный put() является атомарным.

person eboix    schedule 14.12.2011

Чтобы атомизировать его, вам придется использовать синхронизированный, да

Мало того: вы должны поместить синхронизированный блок вокруг каждого общедоступного метода карты, что ухудшит параллелизм.

person OlliP    schedule 16.10.2012