2015-08-27 4 views
5

Я читал в книге, которая читается в ConcurrentHashmap, не гарантирует последнее обновленное состояние, и иногда это может дать более близкое значение. Это верно?Является ли операция чтения в ConcurrentHashMap надежной относительно возвращаемого значения?

Я прочитал его javadocs и многие блоги, которые, кажется, говорят иначе (то есть это точно).

Какое значение верно?

+0

Как вы планируете читать данные? –

+0

используя простой get() –

+1

Тогда вам не стоит беспокоиться, оно вернет самое точное значение. –

ответ

0

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

+1

Если значение не перезаписывается, это не старое значение, оно является текущим ... Конечно, оно не дает вам будущего значения, которое является нормальным – Dici

+0

Да. Но с параллелизмом можно прочитать значение * while *, которое написано. «Обычные» коллекции делают что-то неопределенное, если это происходит. Параллельные коллекции дают вам старое значение или блок до тех пор, пока запись не будет выполнена. – Nitram

+0

Вы не можете посмотреть на 'Collections.SynchronizedCollection' для этого. Это простая низкопроизводительная блокирующая оболочка вокруг обычной коллекции. Взгляните на реализацию ConcurrentHashMap. – Nitram

0

От ConcurrentHashMap javadoc:

операции Retrieval (включая ГЭТ), как правило, не блокируют, поэтому могут перекрываться с операций обновления (в том числе на месте и удалить). Retrievals отражают результаты последних завершенных операций по обновлению с их началом. Для совокупных операций, таких как putAll и clear, одновременное извлечение может отражать вставку или удаление только некоторых записей. Аналогично, итераторы и перечисления возвращают элементы, отражающие состояние хеш-таблицы в какой-то момент времени или после создания итератора/перечисления. Они не выбрасывают ConcurrentModificationException. Однако итераторы предназначены для использования только по одному потоку за раз.

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

+1

Спасибо за очистку. Это выглядит лучше! – bombe

+0

'Collections.synchronizedMap', кажется, синхронизирует ** все ** обращения. Почему этот выбор дизайна в 'ConcurrentHashMap'? – Dici

1

Интуитивно, ConcurrentHashMap должен вести себя как набор изменчивых переменных; Ключами карты являются переменные адреса. get(key) и put(key, value) должны вести себя как волатильное чтение и запись.

Это явно не указано в документе. Тем не менее, я твердо верю, что это так. В противном случае будет много неожиданных, удивительных поведений, которые подрывают логику приложения. Я не думаю, что Дуг Ли сделает это с нами. Конечно, кто-то спрашивает его в списке рассылки concurrency-interest.

Пусть он подчиняется летучими семантику, мы можем причине, основанной на Java модели памяти -

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

Неустойчивое чтение видит непосредственную предшествующую летучую запись и видит только запись. «Предшествующий» здесь соответствует псевдо-временной линии.

Псевдосрочная линия может отличаться от «реальной» линии времени. Однако, теоретически, волатильная запись не может быть бесконечно отложена на псевдо-временной линии. И, по праву, две линии времени довольно близки.

Поэтому мы можем быть уверены, что волатильная запись должна стать видимой «очень быстро» для чтения.

+0

... переменные 'volatile' ... На самом деле, это _is_ указано в контракте API ConcurrentHashMap, но не в этих словах. Javadoc говорит: «... операция обновления для данного ключа несет отношение _happens-before_ с любым (ненулевым) извлечением для этого ключа». Это в основном то же самое, что и «volatile» описывается в JLS: обновление в поле «volatile» устанавливает _happens-before_ с любым последующим чтением того же поля. –

+0

@jameslarge - да, но это только часть изменчивой семантики. нам также нужны 'synchronization-order' и [согласованность порядка синхронизации] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.7) – ZhongYu

+0

возможно, лучший вопрос: «Операции ConcurrentHashMap» последовательно согласованы ». Думаю, это должно быть, или, по крайней мере, люди считают это само собой разумеющимся. – ZhongYu