Это довольно тонкий вопрос, а не глупость.
Несколько потоков, которые считывают структуру данных одновременно, могут делать это без синхронизации, только в том случае, если структура данных была безопасно опубликована. Это проблема видимости памяти, а не проблема времени или состояние гонки.
См. Раздел 3.5 Goetz, et. al., Java Concurrency In Practice, для дальнейшего обсуждения концепции безопасной публикации. Раздел 3.5.4 «Эффективно неизменяемые объекты» здесь применим здесь, поскольку совет становится фактически неизменным в определенный момент, потому что он никогда не записывается после того, как он достиг решенного состояния.
Вкратце, потоки писателей и потоки читателей должны выполнять некоторую координирующую память деятельность, чтобы гарантировать, что потоки читателей имеют последовательное представление о том, что было написано. Например, поток писателя может писать доску sudoku, а затем, удерживая блокировку, храните ссылку на плату в статическом поле. Поток чтения может затем загрузить эту ссылку, удерживая замок. Как только они это сделали, они уверены, что все предыдущие записи на доске видны и последовательны. После этого нити считывателя могут свободно обращаться к структуре платы без дальнейшей синхронизации.
Существуют и другие способы координации видимости памяти, такие как запись/чтение в изменчивую переменную или AtomicReference
. Использование конструкций параллелизма более высокого уровня, таких как защелки или барьеры, или отправка задач на ExecutorService
, также обеспечит гарантии видимости памяти.
UPDATE
на основе обмена в комментариях с Donal Fellows, я хотел бы также отметить, что безопасной публикация требования также применяется при получении результатов назад от чтения потоков. То есть, как только один из потоков читателей будет иметь результат из его части вычисления, он должен опубликовать этот результат где-нибудь, чтобы он мог быть объединен с результатами других потоков читателей. Такие же методы могут быть использованы по-прежнему, например, блокировка/синхронизация по общей структуре данных, летучие вещества и т. Д. Однако это обычно не требуется, поскольку результаты могут быть получены из Future
, возвращенных ExecutorService.submit
или invoke
. Эти конструкции автоматически обрабатывают безопасные требования к публикации, поэтому приложению не нужно иметь дело с синхронизацией.
Исключает ли «фиксированное количество потоков» использование одного потока? –
@JBNizet действительно – fge
Совместное, изменяемое состояние должно быть защищено. – duffymo