JavaRush /Курсы /Модуль 2. Java Core /wait, notify, notifyAll ч.2

wait, notify, notifyAll ч.2

Модуль 2. Java Core
12 уровень , 8 лекция
Открыта

— Привет, Амиго!

И еще пара деталей. Так сказать практических советов.

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

Если коллекция пустая, то ждем
public synchronized Runnable getJob()
{
 if (jobs.size()==0)
  this.wait();

 return jobs.remove(0);
}

В документации по Java очень старательно советуют вызвать метод wait в цикле:

Если коллекция пустая, то ждем
public synchronized Runnable getJob()
{
 while (jobs.size()==0)
  this.wait();

 return jobs.remove(0);
}

Зачем это надо. Дело в том, что таких спящих нитей может быть два десятка. Разбудили всех, а задание забрать сможет только одна. Нить разбудили – но это еще не значит, что условие выполнилось!

Грубо говоря, могут быть «ложные побудки». Хороший разработчик должен учитывать это дело.

— Ясно. А не проще ли тогда использовать просто notify?

— А если в списке больше чем одно задание? Notify обычно советуют использовать ради оптимизации. Во всех остальных случаях рекомендуют использовать метод notifyAll.

— Ок.

— Но и это еще не все. Во-первых, может возникнуть ситуация, когда кто-то унаследовался от твоего класса, добавил туда свои методы и тоже использует wait/notifyAll. Т.е. может быть ситуация, когда на одном объекте висят независимые пары wait/notifyAll, которые друг о друге не знают. Поэтому что надо делать?

— Всегда вызывать wait в цикле и проверять, что условие выхода из цикла действительно выполнилось!

— Правильно. А чтобы тебе стало совсем понятно, что от этого никуда не деться, то многие разработчики указывают на то, что иногда нити просыпаются сами. Нити, которые гарантированно никто не может будить случайно. Похоже это побочный процесс оптимизации/ускорения кода в работающей Java-машине.

— Ничего себе. Понял, без цикла перед wait никуда.

Комментарии (5)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Руслан Уровень 46
20 октября 2025
Очень интересные задачки !!
Артем Уровень 56 Expert
16 мая 2024
На мой взгляд правильное решение в задаче "Расставь wait-notify", не совсем правильное. А именно часть кода в классе MailServer.

         synchronized (mail) {
                mail.wait();
          }
Так как метод wait должен вызваться в цикле, иначе есть шанс, что поток сам проснется, не дожидаясь вызова метода notify. (Согласно документации Oracle)
Misha Saharin Уровень 111 Expert
4 ноября 2022
в задаче "Расставь wait-notify" task2707 - синхронезить весь трай в обоих классах. под одним и тем же монитором, которым пользуются оба класса. wait & notify ставить по смыслу - ты догадаешься.
Greg Уровень 108 Expert
20 октября 2022
Ещё бы пару задачек сюда.
Александр Ц. Уровень 108 Expert
23 июня 2022
Задача com.javarush.task.jdk13.task27.task2706. В методах run классов ConsumerTask и ProducerTask создай необходимые synchronized блоки. Валидатор принял без вышеуказанного условия. Возможно имелось в виду: в методах класса TransferObject проставь synchronized в нужные методы?