Методы wait и notify + syncronized метод

207
22 февраля 2018, 14:00

У меня возник вопрос при рассмотрении кода из связанного вопроса про методы wait и notify (код полностью приведён в этом вопросе, так что дублировать его я не стала). Этот же код был взят из статьи "Методы wait(), notify() и notifyAll()", и вывод при запуске программе, как описано в этой статье, должен быть следующим:

Производитель добавил 1 товар
Товаров на складе: 1
Производитель добавил 1 товар
Товаров на складе: 2
Производитель добавил 1 товар
Товаров на складе: 3
Покупатель купил 1 товар
Товаров на складе: 2
Покупатель купил 1 товар
Товаров на складе: 1
Покупатель купил 1 товар
Товаров на складе: 0
Производитель добавил 1 товар
Товаров на складе: 1
Производитель добавил 1 товар
Товаров на складе: 2
Покупатель купил 1 товар
Товаров на складе: 1
Покупатель купил 1 товар
Товаров на складе: 0

Да и на практике, при запуске программы, я вижу такой вывод. Однако я не могу понять, почему при данном алгоритме получается такой результат.

Процитирую описание алгоритма из ответа на приведённый выше вопрос:

  1. Поток А захватывает lock и входит в синхронизированный код.
  2. Поток А вызывает wait, засыпает и освобождает lock.
  3. Поток Б захватывает lock и входит в синхронизированный код.
  4. Поток Б вызывает notify. Возможно (так как не известно какой поток будет разбужен) поток А просыпается становится в очередь на захват lock.
  5. Поток Б освобождает lock и выходит из синхронизированного кода.
  6. Поток А захватывает lock и продолжает со следующего после wait выражения.

Почему тогда, после того как "производитель добавил первый товар", или, иначе говоря, после того, как был вызван один раз метод put, метод get не вызывается сразу, а только после того, как в методе put будет вызван метод wait?.. Ведь получается, что поток Producer с помощью syncronized входит в синхронизированный код - захватывает монитор объекта Store. Метод wait на этом этапе не вызывается (так как product == 0), product инкрементируется и вызывается метод notify(). И поток Producer выходит из синхронизированного кода - освобождает монитор объекта Store. Получается, что сейчас вполне мог бы выполниться метод get потока Consumer - он должен был быть разбужен методом notify() и product уже равен 1. Однако продолжает выполняться поток Producer, пока у него не вызовется метод wait. Почему, что неверно в моих рассуждениях?

Answer 1

По моему как-то так

Почему тогда, после того как "производитель добавил первый товар", или, иначе говоря, после того, как был вызван один раз метод put, метод get не вызывается сразу, а только после того, как в методе put будет вызван метод wait?

Если метод, объявленный как synchronized, является методом экземпляра, он блокирует монитор, связанный с экземпляром, для которого он вызывается.

Это значит, что метод get не может быть вызван в виду блокировки монитора всего экземпляра. Метод put набирает product >= 3 и вызывает wait.

Если никто не ждет, то notify ничего не делает.

Метод get дождавшись освобождения потока также блокирует монитор всего экземпляра пока не станет true product < 1. Уступает монитор.

Теперь в очереди попеременно происходит уступка монитора, потому что при вызове метода notify() всегда есть ожидающий поток.

upd

Так ведь после завершения работы метода put должен же освободиться монитор, связанный с экземпляром?

Producer выполняет put пока for (int i = 1; i < 6; i++). В каждой итерации в методе put происходит сверка product >= 3 и только тогда монитор экземпляра освобождается через wait. Consumer захватывает монитор.

READ ALSO
Как обновить autowired коллекцию Spring

Как обновить autowired коллекцию Spring

Имеется коллекция объектов

206
Как сохранить фрагменты в памяти?

Как сохранить фрагменты в памяти?

Я использую MVP + Moxy+ BottomNavigation

192
Различие методов getActiveCount() и getTaskCount() ThreadPoolExecutor

Различие методов getActiveCount() и getTaskCount() ThreadPoolExecutor

В чём заключается различие методов getActiveCount() и getTaskCount() класса ThreadPoolExecutor? Правильно, я понимаю, что getActiveCount() - это приблизительное количество...

214
Оптимальная сборка строки

Оптимальная сборка строки

Как эффективней/целесообразней в Java собирать строку из частей? Через Stringformat()

190