Нужна ли дополнительная синхронизация при использовании BlockingQueue?
У меня есть простая bean @Entity Message.java, которая имеет некоторые нормальные свойства. Жизненный цикл этого объекта выглядит следующим образом
Активация сообщения происходит в потоке A, который затем помещается в blockingQueue
Другой поток из пула получает этот объект и выполняет некоторые вещи с ним и изменяет состояние сообщения, после чего объект снова входит в blockingQueue. Этот шаг повторяется до тех пор, пока условие не остановится. Каждый раз, когда объект получает чтение/запись, потенциально может быть из другого потока, но с гарантией, что он будет читать только один поток за раз.
Учитывая эти обстоятельства, мне нужно синхронизировать геттеры/сеттеры? Возможно, свойства нестабильны? или я могу просто уйти без синхронизации?
Спасибо и надеюсь, что смогу прояснить, что у меня здесь.
Ответы
Ответ 1
Нет, вам не нужно синхронизировать доступ к свойствам объекта или даже использовать volatile
для переменных-членов.
Все действия, выполняемые потоком перед тем, как он ставит объект в очередь на BlockingQueue
"произошел-до", объект будет удален. Это означает, что любые изменения, сделанные первым потоком, видны для второго. Это обычное поведение для одновременных коллекций. См. Последний абзац документация класса BlockingQueue
.
Пока первый поток не производит никаких изменений после очередности объекта, он будет безопасным.
Ответ 2
Вам не нужно выполнять синхронизацию самостоятельно, потому что очередь делает это для вас уже.
Видимость также гарантируется.
Ответ 3
Если вы уверены, что только один поток за один раз получит доступ к вашему объекту, вам не потребуется синхронизация.
Однако вы можете убедиться, что с помощью синхронизированного ключевого слова: каждый раз, когда вы хотите получить доступ к этому объекту, и убедитесь, что ни один другой поток не использует один и тот же экземпляр, оберните код в синхронизированный блок:
Message myMessage = // ...
synchronized (myMessage) {
// You're the only one to have access to this instance, do what you want
}
Синхронизированный блок получит неявный блокировку объекта myMessage. Таким образом, ни один другой синхронизированный блок не будет иметь доступ к тому же экземпляру, пока вы не покинете этот блок.
Ответ 4
Казалось бы, вы можете уйти от синхронных методов. Синхронизированный просто блокирует объект, чтобы разрешить доступ к нему только одному потоку. Вы уже обработали это с помощью блокирующей очереди.
Volatile будет полезен, так как это гарантирует, что каждый поток имеет самую последнюю версию вместо значения локального кэша потока.