2009-05-06 3 views
5

Что происходит, когда вы вызываете метод notifyAll на объект, который не ждет? Должно быть исключение или нормальная ситуация?Java - wait and notifyAll

ответ

6

Это абсолютно нормально. Вы можете только оповестить все, что ждет на одном мониторе. Все остальные не заинтересованы. Объект, на который вы вызываете notifyAll, - это только монитор, на котором другие ждут. Если никто не ждет, никто не должен быть уведомлен.

8

Как вы можете видеть здесь, вызов notifyAll() на не ожидающем объекте не имеет никакого эффекта.

alt text

+0

Это может быть не совсем корректно ставить нить в ожидании запуска на notifyAll или, по крайней мере, не без той оговоркой, что первое, что уведомлен нить делает regrab замок монитора. И поскольку только одно из числа уведомляемых потоков может захватить его, остальные будут заблокированы. Но блокировка - это не то же самое, что ждать, потому что заблокированный поток не нуждается в другом сигнале notify(). –

1

Только ожидающие объекты получить уведомление. Object.wait() блокируется до тайм-аута или уведомления - так что остается вопрос, как и почему вы думаете, что объекты, не ожидающие уведомления, когда-либо получат уведомление? это не имеет никакого смысла.

+0

Объекты не ждут или не сообщаются - потоки. И вполне нормально и нормально вызывать notifyAll() на объекте монитора, не зная, есть ли на нем потоки. Например, в сценарии производителя/потребителя с очередью потребитель мог бы освободить очередь и все еще быть занят обработкой, когда производитель добавляет новый элемент в очередь и уведомляет всех пользователей, которые ждут (т. Е. Нет) об этом. –

+0

Я удалил нить, чтобы все было как можно проще. –

2

Объект "ждал", не ожидая себя. Поток - это тот, кто ждет. Если никто не ждет, никто не проснется, и ничего особенного не произойдет.

+0

Что произойдет, когда будильник погаснет, но его никто не услышит? –

2

Совершенно нормальная ситуация.

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

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

1

Я мог бы только раскалывать волосы ;-) Не может быть строго правильным думать о том, что потоки, которые ставятся из состояния ожидания, в состояние «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(); 
     } 
    } 
} 
+0

Может быть упущено уведомление? –