У меня возник вопрос при рассмотрении кода из связанного вопроса про методы 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
Да и на практике, при запуске программы, я вижу такой вывод. Однако я не могу понять, почему при данном алгоритме получается такой результат.
Процитирую описание алгоритма из ответа на приведённый выше вопрос:
Почему тогда, после того как "производитель добавил первый товар", или, иначе говоря, после того, как был вызван один раз метод put, метод get не вызывается сразу, а только после того, как в методе put будет вызван метод wait?.. Ведь получается, что поток Producer с помощью syncronized входит в синхронизированный код - захватывает монитор объекта Store. Метод wait на этом этапе не вызывается (так как product == 0), product инкрементируется и вызывается метод notify(). И поток Producer выходит из синхронизированного кода - освобождает монитор объекта Store. Получается, что сейчас вполне мог бы выполниться метод get потока Consumer - он должен был быть разбужен методом notify() и product уже равен 1. Однако продолжает выполняться поток Producer, пока у него не вызовется метод wait. Почему, что неверно в моих рассуждениях?
По моему как-то так
Почему тогда, после того как "производитель добавил первый товар", или, иначе говоря, после того, как был вызван один раз метод 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 захватывает монитор.
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости