Я бы использовал AtomicReference
. Смотрите мой ответ на аналогичный вопрос. Volatile определенно не достаточно, потому что он только гарантирует, что обновления переменной будут видны другим потокам немедленно (это эффективно отключает кешированный доступ к ней). Однако одновременный доступ к потокам не будет синхронизирован, поэтому может случиться так, что два потока одновременно создадут обновленный Set
, и один из потоков перезапишет изменение других потоков.
Учитывая два потока T1 и T2, которые работают одновременно, представьте следующую последовательность событий:
- T1 читает переменную, текущее состояние V
- T2 читает переменную, текущее состояние V
- T1 вычисляет обновленное состояние V × U1
- T2 вычисляет обновленное состояние V × U2
- T1 обновляет переменную до V × U1
- T2 обновляет переменную до V × U2
Конечное значение из вышеприведенной последовательности будет V × U2, поэтому обновление U1 фактически потеряно.
AtomicReference
, с другой стороны, гарантирует, что переменная обновляется атомарно. Вам нужно будет передать функцию обновления в AtomicReference
, чтобы она вызывалась до атомарного сохранения результата. Убедитесь, что вы используете чистую функцию без побочных эффектов, так как функция обновления может вызываться несколько раз в случае, если в это время ссылка была обновлена атомным способом другим потоком.