Является ли ConcurrentSkipListMap.compute() безопасным для относительных обновлений?
В Javadoc для ConcurrentSkipListMap.compute(K, BiFunction) говорится:
Пытается вычислить сопоставление для указанного ключа и его текущего сопоставленного значения (или ноль, если текущего сопоставления нет). Функция НЕ гарантированно применяется один раз атомарно.
Я понимаю, что эта функция может вызываться несколько раз, но что означает "один раз"?
В частности, безопасно ли вызывать функцию X = X + 1
без увеличения значения карты в несколько раз?
1 ответ
Это говорит о том, что:
- функция может быть вызвана более одного раза, и
- эти звонки могут перекрываться во времени; т.е. если несколько потоков вызывают
compute
одновременно.
Другими словами, не ожидайте атомарного поведения в способе, которым ссылка на функцию вызывается compute
,
В частности, безопасно ли для функции вызывать X = X + 1 без многократного увеличения значения карты?
Это зависит от того, что означает "вызвать X = X + 1". (Вы не включили четкий пример....)
Если
x = x + 1
означает, что вы просто пытаетесь увеличить значение карты, а затем:Один звонок
compute
приведет только к одному "приращению" из-за определения вcompute
вConcurrentMap
,Но когда вы вернетесь из
compute
значение могло быть увеличено более одного раза, потому что другой поток делал то же самое одновременно.
Если
x = x + 1
относится к побочному эффекту ссылки на метод, тогда все ставки выключены:- Это могло случиться несколько раз.
- Если ссылка на ваш метод не синхронизирована должным образом, и так далее, возможны всевозможные неприятные эффекты. Спецификация подразумевает, что
compute
Вызов не будет синхронизироваться извне или вызывать ссылку на метод в мьютексе или что-то в этом роде. Применяются нормальные правила параллелизма / памяти...