Что происходит, когда вы вызываете метод notifyAll на объект, который не ждет? Должно быть исключение или нормальная ситуация?Java - wait and notifyAll
ответ
Это абсолютно нормально. Вы можете только оповестить все, что ждет на одном мониторе. Все остальные не заинтересованы. Объект, на который вы вызываете notifyAll, - это только монитор, на котором другие ждут. Если никто не ждет, никто не должен быть уведомлен.
Как вы можете видеть здесь, вызов notifyAll() на не ожидающем объекте не имеет никакого эффекта.
Только ожидающие объекты получить уведомление. Object.wait() блокируется до тайм-аута или уведомления - так что остается вопрос, как и почему вы думаете, что объекты, не ожидающие уведомления, когда-либо получат уведомление? это не имеет никакого смысла.
Объекты не ждут или не сообщаются - потоки. И вполне нормально и нормально вызывать notifyAll() на объекте монитора, не зная, есть ли на нем потоки. Например, в сценарии производителя/потребителя с очередью потребитель мог бы освободить очередь и все еще быть занят обработкой, когда производитель добавляет новый элемент в очередь и уведомляет всех пользователей, которые ждут (т. Е. Нет) об этом. –
Я удалил нить, чтобы все было как можно проще. –
Объект "ждал", не ожидая себя. Поток - это тот, кто ждет. Если никто не ждет, никто не проснется, и ничего особенного не произойдет.
Что произойдет, когда будильник погаснет, но его никто не услышит? –
Совершенно нормальная ситуация.
Предположим, у вас есть очередь с потоком, в который помещаются элементы-производители, и потоки потребителей, удаляющие из него элементы.
Теперь потребитель мог освободить очередь и все еще занят обработкой, поэтому никто не ждет, чтобы очередь стала непустой. Теперь производитель добавляет новый элемент в очередь. Он должен вызвать notifyAll(), чтобы разбудить потребителя, если он ждет. Добавление дополнительной логики для проверки того, ожидает ли кто-нибудь, и только вызов notifyAll() в этом случае добавит значительную (и очень неустойчивую) сложность сценария - гораздо проще просто вызвать notifyAll() каждый раз.
Я мог бы только раскалывать волосы ;-) Не может быть строго правильным думать о том, что потоки, которые ставятся из состояния ожидания, в состояние «running» на notifyAll; по крайней мере, не обойтись без оговорки, что первая вещь, о которой идет речь, это перезаписать блокировку монитора. И так как только одно из числа уведомленных потоков может захватить его, остальные будут заблокированы. BLOCKED (Thread.State.Blocked) - состояние резьбы. Но блокировка не то же самое, что и ожидалось, потому что заблокированный поток не нуждается в другом сигнале notify() для возобновления. [Ну, я знаю, ложные пробуждения, но, возможно, противоположное может быть справедливо и для некоторых реализаций JVM - пропущенных уведомлений?]
public class HellBoy {
public static class MyThread extends Thread {
static final public Object sharedLock = new Object();
public void run() {
synchronized (sharedLock) {
System.out.println("Gonna wait...");
try {
sharedLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Woken up but sleeping with the lock");
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("exiting and unlocking");
}
}
}
public static void main(String[] args) throws Exception {
new MyThread().start();
new MyThread().start();
new MyThread().start();
new MyThread().start();
Thread.sleep(200);
synchronized (MyThread.sharedLock) {
MyThread.sharedLock.notifyAll();
}
}
}
Может быть упущено уведомление? –
Это может быть не совсем корректно ставить нить в ожидании запуска на notifyAll или, по крайней мере, не без той оговоркой, что первое, что уведомлен нить делает regrab замок монитора. И поскольку только одно из числа уведомляемых потоков может захватить его, остальные будут заблокированы. Но блокировка - это не то же самое, что ждать, потому что заблокированный поток не нуждается в другом сигнале notify(). –