В чем разница между ожиданием / уведомлением и ожиданием / прерыванием?
synchronized (Foo.class) {
while (someCondition) {
try {
Foo.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Кажется, что этот поток просыпается, когда какой-то другой поток вызывает interrupt()
или же notify()
в этой теме. Есть ли различия между ними?
--РЕДАКТИРОВАТЬ--
Я знаю, что один для уведомления объекта, другой прерывает поток. Но оба они приводят к одному и тому же следствию, то есть эта нить пробуждается, поэтому я хочу спросить, как последствия этих двух ситуаций отличаются друг от друга.
3 ответа
Когда поток вызывает notify на каком-либо мониторе, он запускает один поток, который ожидает на этом мониторе, но какой поток пробуждается, определяется планировщиком. (В качестве альтернативы поток может вызвать notifyAll, который пробуждает все потоки, ожидающие этого монитора, затем все они борются за монитор, затем проигравшие возвращаются к ожиданию.) Вот почему цель вызова другая, уведомление сделано на монитор, который говорит планировщику выбрать поток, чтобы проснуться.
В отличие от уведомления, прерывание предназначено для определенного потока. И прерывание не требует, чтобы прерванный поток ожидал на мониторе. Чтобы поток вызвал ожидание на мониторе, он должен сначала получить этот монитор, а затем ожидать освобождения этого монитора, пока поток не завершит ожидание или его прерывание.
Oracle рекомендует использовать прерывание только для отмены. Также классы в java.util.concurrent предназначены для использования прерывания для отмены.
В вашем примере прерывание не будет очень эффективным, потому что управление не покидает цикл while, поток все еще должен проверять состояние, в котором он ожидает, и нет условия в цикле while для определения, установлен ли флаг прерывания. Вероятно, прерванная нить вернется к ожиданию.
Чтобы заставить этот код завершить работу после его прерывания, вместо того, чтобы вернуться к ожиданию, добавьте проверку состояния флага прерывания в условие цикла и задайте в блоке catch флаг прерывания (который сбрасывается при возникновении исключения):
synchronized (Foo.class) {
while (someCondition && !Thread.currentThread().isInterrupted()) {
try {
Foo.class.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
По сути, вы ищете не разницу в учебниках, а разницу в их вариантах использования.
Как уже отмечалось, пробуждение темы - не единственное последствие, а вызов t1.interrupt()
из темы t2
за t1
вызовет InterruptedException
в потоке T1, и это большая разница между Object.notify()
а также Thread.interrupt()
,
Вы должны понимать, что его метод Object.wait()
который бросает проверено InterruptedException
и заставляет вас справиться с этим. Object.wait.
InterruptedException - если какой-либо поток прерывал текущий поток до или в то время, когда текущий поток ожидал уведомления. Прерванное состояние текущего потока очищается при возникновении этого исключения.
Затем вам следует обратиться к этому вопросу, чтобы получить представление об обработке этого исключения.
Разница между ними заключается в том, что один предназначен для связи между потоками для обычного логического программирования (ожидание и уведомление), а другой (прерывание) - для упреждающего отмены / завершения потока даже в случае операций блокировки. Вы должны заметить, что Java не предоставляет какого-либо механизма для упреждающей отмены потока, поэтому вы должны использовать механизм прерывания для этой цели (очевидно, если это необходимо в вашем случае. Вы можете очень хорошо проигнорировать это исключение, если оно не применимо в вашем случае. дело).
Java не ограничивает ваши действия после InterruptedException
и вы можете делать все, что захотите, но не рекомендуется использовать это для других целей, кроме реализации политики отмены потоков. Политика отмены потоков часто игнорируется и является менее обсуждаемой областью, когда программисты пишут многопоточные программы, и именно поэтому вам может быть трудно понять вариант использования.
Что метод API, такой как BlockingQueue.put(..) пытается сказать вам, бросая InterruptedException
является то, что даже его операция блокировки может быть прервана преимущественным образом. Не обязательно, чтобы все блокирующие методы API предоставляли вам такую возможность.
Отмена / прекращение потока с помощью Thread.interrupt()
это не силовой, а кооперативный механизм, это просто запрос, а не приказ.
Ваше использование e.printStackTrace();
Настоятельно не рекомендуется, так как обычно это не ошибка, если вы хотите записать это как ошибку.
Надеюсь, поможет!!
Метод wait используется для приостановки текущего потока на объекте. Метод wait не из класса потока, а из java.lang.Object
Метод уведомления используется для пробуждения потока, ожидающего объекта. Метод уведомления не из класса потока, а из java.lang.Object.
Метод прерывания используется для указания текущего потока, который должен остановить выполнение текущего задания и может запустить другое задание. Метод прерывания из класса потока.
Давайте посмотрим на реальный пример из жизни:
Рассматривайте телефон как объект, личность как нить. Предположим, например, что человек использует телефон, а человек B также хочет использовать телефон, но так как человек, т. Е. (Поток 1), занят им, пока работа не завершена, он не получает блокировку на телефонном объекте B, то есть (поток 2) пытается используйте телефон, но, поскольку A получил блокировку на нем, B переходит в состояние ожидания, пока блокировка не будет снята.
- Если объект "Телефон" вызывает метод ожидания, он ограничит текущий поток, который хочет использовать Телефон, и перейдет в состояние ожидания.
- Если телефонный объект вызывает вызовы, он уведомляет нить, ожидающую, что он установит блокировку и продолжит намеченную работу.
- Если Лицо A(Поток 1) использует объект "Телефон" и находится в какой-то задаче, но вызывается метод прерывания, то A будет дан сигнал о прекращении выполнения текущей задачи и, возможно, потребуется выполнить еще одну назначенную задачу.