Если у меня есть несинхронизированная коллекция java в многопоточной среде, и я не хочу заставлять читателей коллекции синхронизировать [1], это решение, в котором я синхронизирую авторов и использую атомарность справочное присвоение возможно? Что-то типа:
private Collection global = new HashSet(); // start threading after this
void allUpdatesGoThroughHere(Object exampleOperand) {
// My hypothesis is that this prevents operations in the block being re-ordered
synchronized(global) {
Collection copy = new HashSet(global);
copy.remove(exampleOperand);
// Given my hypothesis, we should have a fully constructed object here. So a
// reader will either get the old or the new Collection, but never an
// inconsistent one.
global = copy;
}
}
// Do multithreaded reads here. All reads are done through a reference copy like:
// Collection copy = global;
// for (Object elm: copy) {...
// so the global reference being updated half way through should have no impact
Кажется, что развертывание собственного решения часто дает сбой в подобных ситуациях, поэтому мне было бы интересно узнать другие шаблоны, коллекции или библиотеки, которые я мог бы использовать для предотвращения создания и блокировки объектов для моих потребителей данных.
[1] Причина в том, что большая часть времени тратится на чтение по сравнению с записью, в сочетании с риском возникновения тупиковых ситуаций.
Изменить: много хорошей информации в нескольких ответах и комментариях, некоторые важные моменты:
- В опубликованном мной коде была ошибка. Синхронизация с глобальной (плохо названной переменной) может не защитить синхронизированный блок после подкачки.
- Вы можете исправить это, синхронизируя класс (переместив ключевое слово synchronized в метод), но могут быть и другие ошибки. Более безопасное и удобное в обслуживании решение - использовать что-нибудь из java.util.concurrent.
- В опубликованном мною коде нет «гарантии возможной согласованности». Один из способов убедиться, что читатели действительно видят обновления, сделанные авторами, - это использовать ключевое слово volatile.
- Поразмыслив, общая проблема, которая мотивировала этот вопрос, заключалась в попытке реализовать чтение без блокировки с заблокированной записью в java, однако моя (решенная) проблема была с коллекцией, которая может излишне сбивать с толку будущих читателей. Так что, если не очевидно, что опубликованный мною код работает, позволяя одному писателю за раз вносить изменения в «некоторый объект», который читается без защиты несколькими потоками чтения. Фиксация редактирования осуществляется посредством атомарной операции, поэтому читатели могут получить только «объект» до или после редактирования. Когда / если поток чтения получает обновление, это не может произойти в середине чтения, поскольку чтение происходит на старой копии «объекта». Простое решение, которое, вероятно, было обнаружено и доказано, что оно каким-то образом сломалось до того, как появилась улучшенная поддержка параллелизма в java.
Unsafe
, должен быть достаточно большим красным флагом, чтобы знать, что при его использовании могут произойти неприятности! - person DaoWen   schedule 16.08.2012