По терминологии: существует два вида коллекций, которые называются «неизменяемыми».
- Коллекции, которые выдают исключение при попытке вызвать операцию мутатора (например,
ImmutableMap
в Guava).
- Коллекции, которые при вызове мутатора создают и возвращают новую версию самого себя вместо изменения общего состояния (что-то вроде копирования при записи).
Вы, вероятно, спрашиваете о втором типе "неизменности".
Полагаю, у вас есть что-то вроде этого:
private CopyOnWriteTree tree;
void insertValue(Value value) {
tree = tree.insert();
}
В таком случае использование общей ссылки не представляется полезным.
Если insertValue()
вызывается более чем одним потоком с использованием одной и той же общей ссылки на объект, содержащий поле tree
, то лучшее, что вы можете сделать, это сериализовать обновления этого поля, используя обычные методы, такие как synchronized
, volatile
или AtomicReference
, но один из них будет потерян. (Обратите также внимание, что ссылочная атомарность обновлений здесь не проблема; проблема в том, что без такой синхронизации одному потоку даже не гарантируется, что он когда-либо увидит обновления, сделанные другими потоками).
Коллекции «Копировать при записи» хороши для случаев, когда каждый поток работает со своей собственной копией данных и выбрасывает ее после завершения работы.
Если вам нужны оба обновления, не используйте коллекцию копирования при записи; вместо этого попробуйте какую-нибудь одновременную коллекцию (ConcurrentHashMap
или что-то в этом роде).
PS. Я только что понял, что вопрос был о коллекциях Scala, и я отвечал так же, как и о Java. Тем не менее, логика остается той же, что и модель памяти, то же самое.