В чем отличие notify, notifyall?

217
04 января 2019, 01:00

Я знаю, что notify() - пробуждает любой один поток, а notifyAll() - пробуждает все и даёт доступ одному. Но в чём отличие? в одних случаях работает notify(), а в некоторых нет, но с notifyAll() отлично. Как понять их?

Answer 1

There are two notification methods in the condition queue API — notify and notifyAll. To call either, you must hold the lock associated with the condition queue object. Calling notify causes the JVM to select one thread waiting on that condition queue to wake up; calling notifyAll wakes up all the threads waiting on that condition queue. Because you must hold the lock on the condition queue object when calling notify or notifyAll, and waiting threads cannot return from wait without reacquiring the lock, the notifying thread should release the lock quickly to ensure that the waiting threads are unblocked as soon as possible.
Because multiple threads could be waiting on the same condition queue for different condition predicates, using notify instead of notifyAll can be dangerous, primarily because single notification is prone to a problem akin to missed signals.

© Brian Goetz "Java Concurrency in Practice"

Использование notify потенциально более бережливо к ресурсам - не приходиться выводить потоки из спячки, не приходиться парковать их обратно, потокам не приходиться драться за блокировку и процессор в момент пробуждения. Но в некоторых ситуациях пробуждение только одного потока может приводить к потере сигнала и зависанию программы.

Answer 2

notify() - нотифает только 1 поток, notifyAll() - нотифает все потоки. Может вы пробуждаете не тот поток, который вам нужен, а notifyAll() пробуждает сразу все потоки.

Из вопроса на enSO:

Примером может служить набор потоков, ожидающих завершения определенной задачи; как только задача будет завершена, все ожидающие потоки могут продолжать свою деятельность. В таком случае вы будете использовать notifyAll() для одновременного пробуждения всех ожидающих потоков.

Другой случай, например взаимоисключающая блокировка, только один из ожидающих потоков может сделать что-то полезное после уведомления (в этом случае получить блокировку). В таком случае вы предпочитаете использовать notify().

Полезные различия:

Используйте notify(), если все ваши ожидающие потоки взаимозаменяемы (порядок, который они просыпают, не имеет значения), или если у вас только один ожидающий поток. Общим примером является пул потоков, используемый для выполнения заданий из очереди - при добавлении задания один из потоков уведомляется о пробуждении, выполняет следующее задание и возвращается в режим сна.

Используйте notifyAll() для других случаев, когда потоки ожидания могут иметь разные цели и должны иметь возможность запускать одновременно. Примером может служить операция обслуживания совместно используемого ресурса, где несколько потоков ждут завершения операции перед доступом к ресурсу.

Answer 3

Если коротко и без занудства - notify будит один какой то рандомный поток, notifyAll - (внезапно

READ ALSO
Генерация POJO классов из из схемы данных в виде файла .xml?

Генерация POJO классов из из схемы данных в виде файла .xml?

Всем привет, подскажите пожалуйста, как можно cгенерировать POJO классы из схемы данных в виде файлаxml?

159
Можно ли отсортировать ArrayList?

Можно ли отсортировать ArrayList?

Имеется ArrayList вида String : intКак отсортировать его по возрастанию/убыванию по "колонке" int ?

154
Первая JVM для платформы Java SE

Первая JVM для платформы Java SE

Собственно говоря, сам вопрос кроется в залоговке данной темыЗнаю, что примерно с 2002 года освной реализацией JVM для платформы Java SE является...

193
Проблема с загрузками ресурсов в JSP

Проблема с загрузками ресурсов в JSP

У меня в папке webapp есть другая папка - static (webapp/static)В этой папке у меня лежат ресурсы: изображения, скрипты, каскадные стили

152