2010-09-07 2 views
13

У меня есть простой bean @Entity Message.java, который имеет некоторые нормальные свойства. Жизненный цикл этого объекта заключается в следующемНужна ли дополнительная синхронизация при использовании BlockingQueue?

Инстанцирование Послания происходит на тему А, который затем установлены в очередь в BlockingQueue

Другой поток из пула получает этот объект и сделать некоторые вещи с ним и изменяет состояние сообщения, после этого объект снова входит в blockingQueue. Этот шаг повторяется до тех пор, пока условие не остановится. Каждый раз, когда объект получает чтение/запись, потенциально может быть из другого потока, но с гарантией, что только один поток за раз будет читать/писать.

Учитывая, что мне нужно синхронизировать геттеры/сеттеры? Возможно, свойства нестабильны? или я могу просто уйти без синхронизации?

Спасибо и надеюсь, что смогу прояснить, что у меня здесь.

ответ

25

Нет, вам не нужно синхронизировать доступ к свойствам объекта или даже использовать volatile для переменных-членов.

Все действия, выполняемые потоком перед его очередью на объект BlockingQueue «случится раньше», объект будет удален. Это означает, что любые изменения, сделанные первым потоком, видны для второго. Это обычное поведение для одновременных коллекций. См. Последний абзац the BlockingQueue class documentation.

До тех пор, пока первый поток не будет вносить никаких изменений после очередности объекта, он будет безопасным.

+2

+1 для упоминания семантики видимости потока BlockingQueue. – Darron

2

Если вы уверены, что только один поток за один раз получит доступ к вашему объекту, вам не потребуется синхронизация.

Однако, вы можете быть уверены, что с помощью синхронизированных ключевое слово: каждый раз, когда вы хотите получить доступ к этому объекту, и быть уверенным, что никакой другой поток использует тот же экземпляр, оберните ваш код в синхронизированный блок:

Message myMessage = // ... 
synchronized (myMessage) { 
    // You're the only one to have access to this instance, do what you want 
} 

Синхронизированный блок получит неявный замок объекта myMessage. Таким образом, ни один другой синхронизированный блок не будет иметь доступ к тому же экземпляру, пока вы не покинете этот блок.

+0

Синхронизация отдельных геттеров и сеттеров на самом деле ничего не доказывает, если на самом деле два элемента должны чередоваться друг с другом. Они все равно будут видеть это в непоследовательных состояниях/частично переписывать. Этот ответ является лучшим способом решения проблемы. – Affe

+0

@Vivien_Barousse, поэтому мне фактически не нужно ничего синхронизировать, потому что не будет доступ одновременно. Это отвечает на мой вопрос, спасибо! –

3

Вам не нужно выполнять синхронизацию самостоятельно, потому что очередь делает это за вас уже.

Видимость также гарантирована.

0

Казалось бы, вы могли бы уйти от синхронных методов. Синхронизированный просто блокирует объект, чтобы разрешить доступ к нему только одному потоку. Вы уже справились с этой блокировкой.

Volatile будет полезен, так как это гарантирует, что каждый поток имеет самую последнюю версию, вместо значения локального кеша потока.

+0

Использование 'volatile' с' BlockingQueue' не требуется (и неэффективное дублирование усилий); часть контракта «BlockingQueue» заключается в том, что любые действия потока перед установкой объекта «произойдут раньше», объект отбрасывается другим потоком. – erickson

+0

Полезно знать. Я знал, что волатильность необходима, когда другой поток изменяет значение поля. Имеет смысл, что блокирующий поток позаботится об этом, так как текущий поток запрашивает значение. – tylermac

Смежные вопросы