Это поточно-безопасный. Тем не менее, способ быть потокобезопасным может быть не тем, что вы ожидаете.Есть некоторые «подсказки» вы можете видеть:
Этот класс полностью совместим с Hashtable
в программах, которые полагаются на его безопасности потока, а не на деталях синхронизации
Чтобы узнать всю историю в более полной картине вам необходимо знать интерфейс ConcurrentMap
.
Оригинал Map
содержит некоторые очень простые методы чтения/обновления. Даже я смог сделать потокобезопасную реализацию Map
; есть много случаев, когда люди не могут использовать мою Карту, не учитывая мой механизм синхронизации. Это типичный пример:
if (!threadSafeMap.containsKey(key)) {
threadSafeMap.put(key, value);
}
Этот фрагмент кода не является потокобезопасным, хотя сама карта является. Два потока, вызывающие containsKey()
, в то же время могли думать, что такого ключа нет, поэтому оба они вставляют в Map
.
Для устранения проблемы нам необходимо выполнить дополнительную синхронизацию явно. Предположим, нить-безопасность моей карты достигается синхронизированным ключевых слов, вам нужно будет сделать:
synchronized(threadSafeMap) {
if (!threadSafeMap.containsKey(key)) {
threadSafeMap.put(key, value);
}
}
Такой дополнительный код нужен, чтобы вы знали о «деталях синхронизации» карты. В приведенном выше примере нам нужно знать, что синхронизация выполняется посредством «синхронизации».
ConcurrentMap
интерфейс делает этот шаг дальше. Он определяет некоторые общие «сложные» действия, которые включают в себя множественный доступ к карте. Например, приведенный выше пример показан как putIfAbsent()
. При этих «сложных» действиях пользователям ConcurrentMap
(в большинстве случаев) не требуется синхронизировать действия с множественным доступом к карте. Следовательно, реализация карты может выполнять более сложный механизм синхронизации для повышения производительности. ConcurrentHashhMap
- хороший пример. Фактическая безопасность потоков поддерживается, сохраняя отдельные блокировки для разных разделов карты. Это потокобезопасно потому что одновременный доступ к карте будет не повредить внутренние структуры данных, или вызвать любое обновление потеряли неожиданное и т.д.
со всеми выше в виду, смысл Javadoc будет яснее:
«Операции поиска (включая get) обычно не блокируют», потому что ConcurrentHashMap
не использует «синхронизированный» для обеспечения безопасности потоков. Логика get
сама по себе заботится о безопасности потоков; и если вы смотрите далее в Javadoc:
Таблица внутренне разделена, чтобы попытаться разрешить указанное количество одновременных обновлений без раздора
не только поиск без блокировки, даже обновления может происходят одновременно. Однако неблокирующие/одновременные обновления не означают, что он небезопасен. Это просто означает, что он использует некоторые способы, кроме простых «синхронизированных» для обеспечения безопасности потоков.
Однако, поскольку внутренний механизм синхронизации не отображается, если вы хотите выполнить некоторые сложные действия, отличные от тех, которые предусмотрены ConcurrentMap
, вам может потребоваться изменить вашу логику или не использовать ConcurrentHashMap
.Например:
// only remove if both key1 and key2 exists
if (map.containsKey(key1) && map.containsKey(key2)) {
map.remove(key1);
map.remove(key2);
}
Если я читаю это право, это означает, что поиск всегда будет возвращать результаты последнего обновления для завершения - в момент начала поиска. Это означает, что полное обновление может происходить между временем, когда поиск начинается и завершается, и он не изменит результат упомянутого поиска. – Aurand