2009-05-06 14 views
5

Cosa succede quando si chiama notifyAll su un oggetto che non è in attesa? Dovrebbe esserci un'eccezione o è una situazione normale?Java - wait and notifyAll

risposta

6

È completamente normale. È possibile notificare tutto ciò che è in attesa su un singolo monitor. Tutti gli altri non sono interessati. L'oggetto su cui si chiama notifyAll è solo il monitor su cui gli altri stanno aspettando. Se nessuno sta aspettando nessuno deve essere avvisato

8

Come potete vedere qui, chiamare notifyAll() su un oggetto non in attesa non ha alcun effetto.

alt text

+0

Potrebbe non essere strettamente corretto di mettere un filo da in attesa di esecuzione su notifyAll o almeno non senza l'avvertenza che la prima cosa che un filo notificato non è regrab il blocco del monitor. E poiché solo uno dei numerosi thread notificati può prenderlo, gli altri verranno bloccati. Ma il blocco non equivale ad aspettare perché il thread bloccato non ha bisogno di un altro segnale notify(). –

1

Solo in attesa Oggetti ricevere la notifica. Object.wait() blocca fino a un timeout o notifica - quindi la domanda rimane come o perché penseresti che non aspettare che gli oggetti vengano mai notificati? non ha senso.

+0

Gli oggetti non attendono o vengono notificati - i thread lo fanno. Ed è perfettamente possibile e normale chiamare notifyAll() su un oggetto monitor senza sapere se ci sono thread in attesa su di esso. Ad esempio, in uno scenario produttore/consumatore con una coda, il consumatore potrebbe aver svuotato la coda ed essere ancora occupato con l'elaborazione quando il produttore aggiunge un nuovo elemento alla coda e avvisa tutti i consumatori che stanno aspettando (cioè nessuno) su questo. –

+0

Ho eliminato Thread per mantenere le cose il più semplici possibile. –

2

L'oggetto è "atteso", non in attesa. Il thread è colui che sta aspettando. Se nessuno sta aspettando, nessuno si sveglierà e non succederà nulla di speciale.

+0

Cosa succede quando scatta un allarme ma nessuno lo sente? –

2

Situazione perfettamente normale.

Supponiamo di avere una coda con un thread di produzione che inserisce elementi in esso e un thread di consumo che rimuove elementi da esso.

Ora il consumatore potrebbe aver svuotato la coda ed essere ancora occupato con l'elaborazione, quindi nessuno sta aspettando che la coda diventi non vuota. Ora il produttore aggiunge un nuovo elemento alla coda. Deve chiamare notifyAll() per svegliare il consumatore se fosse in attesa. Aggiungendo una logica aggiuntiva per verificare se qualcuno è in attesa e solo chiamando notifyAll() in quel caso aggiungerebbe una notevole (e molto soggetta a errori) la complessità dello scenario - è molto più facile chiamare ogni volta notAttivAll().

1

Potrei stare solo spaccando i capelli ;-) Potrebbe non essere del tutto corretto pensare che i thread vengano messi dallo stato "in attesa" allo stato "in esecuzione" su notifyAll; almeno non senza l'avvertenza che la prima cosa che fa un thread notificato è registrare il blocco del monitor. E poiché solo uno dei thread notificati è in grado di afferrarlo, gli altri saranno bloccati. BLOCCATO (Thread.State.Blocked) è lo stato del thread. Ma il blocco è non è lo stesso che aspettare perché il thread bloccato non ha bisogno di un altro segnale di notifica() per riprendere. [Bene, so di risvegli spuri ma forse potrebbe anche essere vero il contrario per alcune implementazioni JVM: una notifica mancata?]

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

Può essere notificata una notifica? –