2011-11-18 6 views
6

Ecco un caso in cui un thread è in attesa di notify() o di un timeout. Qui viene aggiunto un ciclo while per gestire la sveglia spuria.Java: Come distinguere tra wakeful spurio e timeout in attesa()

boolean dosleep = true; 
while (dosleep){ 
    try { 
     wait(2000); 
     /** 
     * Write some code here so that 
     * if it is spurious wakeup, go back and sleep. 
     * or if it is timeout, get out of the loop. 
     */ 

    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

In questo caso come posso distinguere tra un risveglio spuria e time out? Se si tratta di una sveglia spuria, ho bisogno di tornare indietro e aspettare. E se è un timeout, ho bisogno di uscire dal giro.

Posso facilmente identificare il caso di notify(), perché imposterò la variabile dosleep su false durante la chiamata a notify().

EDIT: sto usando la versione 1.4 java, a causa dei requisiti del progetto incorporato. Non riesco a utilizzare Condition dato che è disponibile solo per il post 1.5.

Grazie in anticipo.

+0

Bringer128 ha una soluzione ragionevole, ma, mi chiedo perché vuoi farlo. L'Interrupt non è generalmente un "wakeful spurio", è un segnale per interrompere e _ fermare il processo. – user949300

+0

Non si tratta di interrupt. Un "wakeful spurio" può venire in qualsiasi momento. Se arriva nello stesso tempo dopo che sono entrato nell'attesa(), non voglio uscire dal ciclo allora. Ho bisogno di aspettare che attendo il tempo di timeout prima di uscire dal ciclo –

+0

che vedo. Non ti stai interrompendo, ma qualche altro thread sta chiamando notify() o, più probabilmente, notifyAll(), e ti sei svegliato. – user949300

risposta

4

È necessario tenere traccia del timeout se si desidera distinguere i due casi.

long timeout = 2000; 
long timeoutExpires = System.currentTimeMillis() + timeout; 
while(dosleep) { 
    wait(timeout); 
    if(System.currentTimeMillis() >= timeoutExpires) { 
    // Get out of loop 
    break; 
    } 
} 

Detto questo, la raccomandazione di denis di utilizzare la classe Condition è il modo migliore per farlo.

+0

Questo codice attende di nuovo l'intero timeout dopo che si è verificata la sveglia anomala e che non è corretta. La risposta di Cameron Skinner è corretta ed è anche retrocompatibile con JDK v4 (mentre la risposta di Denis.Solonenko è corretta, usa l'API 'java.concurrency' e, quindi, ha bisogno di JDK v5 +). Questo è il mio bit per l'argomento. –

+2

Non utilizzare System.currentTimeMillis() utilizzare invece una qualche forma di tempo monotonico poiché questo è soggetto a comportamenti anomali quando viene modificato l'orologio di sistema. http://stackoverflow.com/questions/351565/system-currenttimemillis-vs-system-nanotime –

+0

Come ha fatto notare Jiri Patera, l'esempio è imperfetto di per sé. Inoltre, oltre alla "Classe di condizioni" in realtà un'interfaccia, il JavaDoc di [Condizione] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html) afferma chiaramente che "Un'implementazione è libera di rimuovere la possibilità di wakeups spurie, ma si raccomanda che i programmatori di applicazioni suppongano sempre che possano verificarsi e quindi aspettano sempre in un ciclo". Cameron Skinner ha l'unica risposta giusta. –

4

Credo che Lock s e Condition si adattino meglio alle vostre esigenze in questo caso. Si prega di controllare il javadocs per Condition.awaitUntil() - ha un esempio di utilizzo

+1

sto usando la versione 1.4 java, a causa del requisito del progetto incorporato. Ho paura che la condizione sia disponibile solo dopo l'1.5. –

6

Si potrebbe fare questo:

boolean dosleep = true; 
long endTime = System.currentTimeMillis() + 2000; 
while (dosleep) { 
    try { 
     long sleepTime = endTime - System.currentTimeMillis(); 
     if (sleepTime <= 0) { 
      dosleep = false; 
      } else { 
      wait(sleepTime); 
     } 
    } catch ... 
} 

Questo dovrebbe funzionare bene in Java 1.4, e farà in modo che il thread dorme per almeno 2000 ms.