Задача состоит в том, чтобы отслеживать некоторые запущенные процессы. Сохранение этой информации в памяти просто прекрасно, поэтому я использую параллельную хэш-карту для хранения этих данных:
ConcurrentHashMap<String, ProcessMetaData> RUNNING_PROCESSES = new ConcurrentHashMap();
С безопасным размещением новых объектов на карте все в порядке, проблема в том, что состояние этих процессов меняется, поэтому мне приходится время от времени обновлять ProcessMetaData
. Я сделал ProcessMetaData
неизменяемым и использовал метод compute()
ConcurrentHashMap
для обновления значений, но теперь проблема в том, что ProcessMetaData
усложняется, и сохранение неизменности становится трудно управляемым. Вопрос в том, что пока я обновляю только ProcessMetaData
в атомарном (согласно javadoc) методе compute()
, объект может быть изменчивым, и в целом все по-прежнему будет потокобезопасным? Верно ли мое предположение?
ProcessMetaData
использует вычисления, тогда да. В противном случае читатели увидят расы, поскольку они изменяются под ними (например, эквивалентно использованиюsynchronized (processMetaData) { ... }
). Неизменяемый экземпляр означает, что читателям не нужно работать под монопольной блокировкой, поэтому, если вы удалите ее, вам нужно координировать свои действия. - person Ben Manes   schedule 02.06.2021compute
задокументировано какatomic
, означает, что он также предоставляетvisibility
? Теоретически реализация может блокировать разные блокировки для чтения и записи (придуманный пример), поэтому в таком случае читатели не гарантируют, что увидят обновления. - person Eugene   schedule 02.06.2021compute
не задокументирован ни с какими гарантиями до того, как произойдет, как и с классом. Единственная гарантия исходит от пакетаjava.util.concurrent
с: Действия в потоке до помещения объекта в любую параллельную коллекцию происходят до действий, следующих за доступом или удалением этого элемента из коллекции в другом потоке, но это все еще не достаточно сказать, чтоcompute
предлагает необходимые гарантии в отношенииhappens-before
. - person Eugene   schedule 02.06.2021ConcurrentHashMap
, вообще не использует блокировку. Да, это отличается от того, что делаетcompute
, и делает операциюcompute
, которая изменяет уже сохраненный объект неатомарным в отношении операций извлечения. Но даже если вы используете толькоcompute
, вам не разрешается использовать возвращаемое значение, поскольку это не будет частью атомарной операции. - person Holger   schedule 03.06.2021get
сcompute
небезопасно, поэтомуget
говорит, что это может перекрываться. Я понимаю. Вопрос, который у меня был, былcompute
для обновлений,compute
для поиска, как Бен предложил ранее. - person Eugene   schedule 03.06.2021compute
для извлечения — это другая проблема, так как, конечно, он будет воспринимать завершенное состояние обновления, которое он только что выполнил в том же потоке. Проблемы начинаются, как объяснено в моем ответе, с другими операциямиcompute
при использовании полученного значения. Нет упорядочения и видимости памяти (как это могло быть?) при использовании извлеченного значения, в то время как другиеcompute
операции изменяют его. - person Holger   schedule 03.06.2021