Почему ConcurrentHashMap.putifAbsent является безопасным? - PullRequest
9 голосов
/ 14 мая 2011

Со вчерашнего дня я читаю для конкретности, и многого не знаю ... Однако некоторые вещи начинают проясняться ...
Я понимаю, почему двойная проверка блокировки небезопасна (интересно, какова вероятностьвозникает редкое условие) но volatile решает проблему в 1.5 + ....
Но мне интересно, если это происходит с putifAbsent

like ...

myObj = new myObject("CodeMonkey");
cHashM.putIfAbsent("keyy",myObj);  

Тогдаэто гарантирует, что myObj будет на 100% сглаженным, когда другой поток делает cHashM.get() ???Потому что у него может быть ссылка не полностью инициализирована (проблема двойной проверки блокировки)

Ответы [ 4 ]

4 голосов
/ 14 мая 2011

Если вы вызываете concurrentHashMap.get(key) и он возвращает объект, этот объект гарантированно будет полностью инициализирован. Каждый пут (или putIfAbsent) получит блокировку, специфичную для сегмента, и добавит элемент к записям блока.

Теперь вы можете просмотреть код и заметить, что метод get не получает такую ​​же блокировку. Таким образом, вы можете утверждать, что может быть устаревшее чтение, что также не соответствует действительности. Причина в том, что значение в самой записи является изменчивым. Таким образом, вы обязательно получите самую свежую информацию.

4 голосов
/ 14 мая 2011

putIfAbsent метод в ConcurrentHashMap - это метод проверки, если отсутствует, а затем установлен.Это атомная операция.Но чтобы ответить на следующую часть: «Тогда это гарантирует, что myObj будет на 100% инициализирован, когда другой поток выполнит cHashM.get ()», это будет зависеть от того, когда объект помещен в HashMap.Обычно существует приоритет «перед случаем», т. Е. Если вызывающий объект получает первым до размещения объекта на карте, тогда возвращается null, в противном случае возвращается значение.

2 голосов
/ 14 мая 2011

Соответствующая часть документации такова:

Эффекты согласованности памяти: Как и в случае других параллельных коллекций, выполняются действия в потоке перед помещением объекта в ConcurrentMap в качестве ключа или значения.перед действиями после доступа или удаления этого объекта из ConcurrentMap в другом потоке.

- java.util.ConcurrentMap

Итак, у вас есть случается до отношений.

1 голос
/ 14 мая 2011

Я не эксперт в этом, но, глядя на реализацию Segment в ConcurrentHashMap, я вижу, что поле volatile count, кажется, используется для обеспечения надлежащей видимости между потоками.Все операции чтения должны читать поле count, а все операции записи должны записывать в него.Из комментариев в классе:

Read operations can thus proceed without locking, but rely
on selected uses of volatiles to ensure that completed
write operations performed by other threads are
noticed. For most purposes, the "count" field, tracking the
number of elements, serves as that volatile variable
ensuring visibility.  This is convenient because this field
needs to be read in many read operations anyway:

   - All (unsynchronized) read operations must first read the
     "count" field, and should not look at table entries if
     it is 0.

   - All (synchronized) write operations should write to
     the "count" field after structurally changing any bin.
     The operations must not take any action that could even
     momentarily cause a concurrent read operation to see
     inconsistent data. This is made easier by the nature of
     the read operations in Map. For example, no operation
     can reveal that the table has grown but the threshold
     has not yet been updated, so there are no atomicity
     requirements for this with respect to reads.
...