Блокировка на уровне объекта

Реализована блокировка на уровне объекта для доступа к устройству:

private static Object device_locker_ = new Object();

public Device getDevice() {
   synchronized (device_locker_) {
       return device_;
   }

}

Вопрос, могут ли разные потоки в данном случае работать с устройством, вызывая разные методы через getDevice()? Примеры:

getDevice().getDeviceInfo()
getDevice().changePIN()
getDevice().doSomething()

Т.е. гарантируется ли в данном случае, что только один поток может работать с устройством?


Ответы (1 шт):

Автор решения: kami

гарантируется ли в данном случае, что только один поток может работать с устройством?

Нет. В представленном в вопросе коде гарантируется, что блок, экранированный с помощью synchronized не будет доступен для одновременного выполнения несколькими потоками. А всё остальное - по прежнему может выполняться параллельно.

В целом, код

getDevice().getDeviceInfo()
getDevice().changePIN()
getDevice().doSomething()

эквивалентен следующему:

device = getDevice(); // этот код всегда будет выполняться только одним потоком *.
device.getDeviceInfo(); // а здесь уже разрешено параллельное выполнение
// аналогично - для других примеров вызовов методов
  • Строго говоря, этот код не является полным аналогом примеров выше. Первая строчка "эквивалента" не полностью будет выполнена в рамках одного потока. Присвоение результата работы метода getDevice() уже не ограничено ключевым словом synchronized, поэтому если device является разделяемой переменной - потоки станут конкурировать за её заполнение.

Если внутри методов getDeviceInfo(), doSomething(), etc... производятся действия, параллельное выполнение которых несколькими потоками может привести к нежелательным последствиям (например - отправка команд на устройство потенциально может привести к смешению данных и как следствие - к ошибке протокола обмена) - именно эти действия необходимо ограничивать выполнением в рамках одного потока.

→ Ссылка