Как использовать ConcurrentHashMap в Java

До Java 1.5, если вам нужна была реализация Map, которую можно безопасно использовать в многопоточной Java-программе, у вас были только Hashtable или synchronized Map, потому что HashMap НЕ безопасен.

ConcurrentHashMap был представлен как альтернатива Hashtable в Java 1.5 как часть пакета многопоточности. C ConcurrentHashMap у вас есть лучший выбор, не только потому, что это безопасно в многопоточном окружении, но так же предоставляет лучшую производительность по сравнению с Hashtable и synchronizedMap. ConcurrentHashMap работает производительнее, потому что блокирует лишь часть Map. Позволяет одновременные операции чтения и в тоже время обеспечивает целостность, синхронизируя операции записи.

В этой статье мы изучим:
  • Как реализован ConcurrentHashMap в Java.
  • Некоторые важные свойства ConcurrentHashMap.
  • Когда стоит использовать ConcurrentHashMap.

Как реализован ConcurrentHashMap в Java

ConcurrentHashMap был разработан как альтернатива Hashtable и обеспечивает всю функциональность, предоставляемой Hashtable, с дополнительными возможностями, называемые уровень одновременности (concurrency level). ConcurrentHashMap позволяет множеству читателей одновременное чтение без использования блокировок. Это достигается разделением Map на различные части, основываясь на «уровне одновременности» и блокированием только части Map при обновлении. По умолчанию, уровень одновременности равен 16, и соответственно Map разделяется на 16 частей и каждая часть управляется отдельной блокировкой. Это означает, что 16 потоков могут оперировать Map одновременно, пока они работают с разными частями Map. Это делает ConcurrentHashMap высокопроизводительным, в тоже время не ухудшая потоко-безопасность.

Некоторые важные свойства ConcurrentHashMap

Но существует особенности. Поскольку операции обновления не синхронизирующие, одновременная выборка данных может не показать недавние изменения.

Так же стоит помнить об особенностях итерации по Map. Итератор, возвращаемый keySet, несогласованный и отражает состояние ConcurrentHashMap на определенный момент и может не отражать недавние изменения. Он так же является fail-safe и не выбрасывает исключение ConcurrentModificationException.

Уровень параллельности по умолчанию равен 16 и может быть изменен во время создания ConcurrentHashMap. Поскольку данный уровень используется «под капотом» и указывает на число одновременных обновлений без конкуренции, в случае наличия лишь нескольких обновляющих потоков, имеет смысл использовать небольшое значение.

ConcurrentHashMap не позволяет хранить null.

ConcurrentHashMap предоставляет метод putifAbsent(key, value), который позволяет добавить в Map ключ-значение, в случае отсутствия данной записи, причем сделать это атомарно, недопустив состояния гонки. Известный подход проверить-на-отсутствие-и-вставить (get, put) для ConcurrentHashMap не работает, поскольку во время операции вставки put() вся Map не заблокирована, и пока один поток добавляет значение, вызов get() в другом потоке все еще может вернуть null, и как следствие — один поток может переписать значение, добавленное другим потоком. Конечно, вы можете обернуть код синхронизирующим блоком, сделав его потоко-безопасным, но это лишь сделает ваш код одно-поточным.

Когда следует использовать ConcurrentHashMap в Java

ConcurrentHashMap отлично подходит, когда у вас множество читающих потоков и несколько пишущих. Если число пишущих превосходит или даже равно числу читающих, то производительность ConcurrentHashMap уменьшается до уровня synchronizedMap и Hashtable. Производительность ConcurrentHashMap падает, поскольку происходит блокировка всей Map, и каждый читающий поток ждет пишущего, который работает с этой областью Map.

ConcurrentHashMap хороший выбор для кэшей, которые могут быть инициализированы во время старта приложения и позже предоставлять доступ запрашивающим потокам.

ConcurrentHashMap хороший заменитель Hashtable и может быть использован повсеместно, однако следует помнить об особенностях синхронизации у ConcurrentHashMap по сравнению с Hashtable.

На этом пока все. Если у вас есть вопросы или комментарии - буду рад их услышать. Присоединяйтесь к беседе!

Если вам понравилась статья - делитесь с друзьями, подписывайтесь на блог.

Share with friends

Comments


Nuance of Java development

This blog is about Java development and explores only unfamiliar topics.
Most part of blog is written in Russian.

Search

Search on site and blog.