Простой ответ - да, вам нужна синхронизация.
Если вы когда-либо пишете в поле и читаете его откуда-либо еще без какой-либо синхронизации, ваша программа может увидеть несовместимое состояние и, вероятно, ошибиться.Ваша программа не завершится сбоем, но может увидеть либо старые, либо новые, либо (в случае длинных и двойных) наполовину старые и наполовину новые данные.
Когда я говорю «некоторая форма синхронизации», я имею в виду нечто более точное, что создает отношение «происходит до» (так называемый барьер памяти) между точками записи и чтения.Классы синхронизации или java.util.concurrent.lock являются наиболее очевидным способом создания такой вещи, но все параллельные коллекции обычно также предоставляют аналогичные гарантии (проверьте javadoc, чтобы быть уверенным).Например, выполнение параллельных очередей «положить» и «взять» создаст отношение «до того, как произойдет».
Пометка поля как изменчивого не дает вам видеть непоследовательные ссылки (длинные разрывы) и гарантирует, что все потоки «увидят»"написать.Но изменяемые поля записи / чтения не могут быть объединены с другими операциями в больших элементарных единицах.Классы Atomic обрабатывают общие комбинированные операции, такие как сравнение и установка или чтение и увеличение.Синхронизация или другие java.util.concurrent синхронизаторы (CyclicBarrier и т. Д.) Или блокировки должны использоваться для больших областей исключительности.
Отходя от простого да, есть случаи, которые больше "нет", если вы действительно знаетечто ты делаешь".Два примера:
1) Особый случай поля, которое является окончательным и записывается ТОЛЬКО во время построения.Одним из примеров этого является заполнение предварительно вычисленного кеша (например, карта, где ключи - это общеизвестные значения, а значения - предварительно вычисленные производные значения).Если вы строите это в поле перед созданием, и поле является окончательным, и вы никогда не пишете в него позже, конец конструктора выполняет «окончательное замораживание поля» и последующие операции чтения НЕ требуют синхронизации.
2) Случай шаблона "racy single check", который рассматривается в Effective Java.Канонический пример находится в java.lang.String.hashCode ().Строка имеет поле хеша, которое лениво вычисляется при первом вызове hashCode () и кэшируется в локальное поле, которое НЕ синхронизируется.По сути, несколько потоков могут стремиться вычислить это значение и установить его для других потоков, но потому что оно защищено хорошо известным sentinel (0) и всегда вычисляет одинаковое значение (поэтому нам не важно, какой поток "выиграет" илинесколько делать), это на самом деле гарантированно будет в порядке.
Более длинная ссылка (написано мной): http://refcardz.dzone.com/refcardz/core-java-concurrency