2010-08-03 9 views
19

Avere questa dichiarazione di attesa:Come distinguere quando si attende (lungo timeout) l'uscita per la notifica o il timeout?

public final native void wait(long timeout) throws InterruptedException; 

Potrebbe uscire dal InterruptedException, o per timeout, o perché Notifica/notifyAll metodo è stato chiamato in un altro thread, Eccezione è facile prendere, ma ...

Ci è un modo per sapere se la causa delle uscite era il timeout o la notifica?

EDIT:

Questo è un modo ingannevole che potrebbe funzionare, (anche se non mi piace)

  long tBefore=System.currentTimeMillis(); 
      wait(TIMEOUT); 
      if ((System.currentTimeMillis() - tBefore) > TIMEOUT) 
      { 
       //timeout 
      } 
+2

Avevo un'esigenza simile e nel mio caso si è scoperto che un "semaforo" era più adatto; 'Semaphore.tryAcquire (long timeout, TimeUnit unit)' restituisce 'false' se il timeout è scaduto. – Santosh

+0

Il semaforo funzionerebbe a meno che non sia necessario attendere, cosa che non è supportata dal contratto pubblico del semaforo. –

risposta

7

Non è possibile distinguere tra i due, a meno che fornisci qualche ulteriore codice. Per esempio con l'aggiunta di un ThreadLocalBoolean che è impostato per true solo su notify()

Ma prima è necessario assicurarsi che la logica richiede questa differenziazione.

+4

L'OP sapeva già che un'eccezione non veniva generata e desidera distinguere tra un timeout e una notifica. Questo non fornisce alcuna informazione utile a tal fine. –

+1

grazie, ho frainteso l'OP. Aggiornato ora. – Bozho

+0

+1 per riscrivere, e sì un booleano e un metodo sincronizzato è quello che sto usando ora –

1

L'eccezione non viene generata su notifica e timeout.

Penso che sia meglio fare affidamento sugli oggetti di sincronizzazione pacchetto java.lang.concurrent invece di utilizzare Object.wait().

12

Questo non risponde esattamente alla domanda, ma probabilmente risolverà il problema: utilizzare meccanismi di concorrenza di livello superiore. L'attesa/notifica di solito è più bassa di quanto si desideri, per questo motivo tra molti altri.

Ad esempio, se si stesse utilizzando BlockingQueue.poll(long, TimeUnit), è possibile verificare se il risultato è nullo sapere se è scaduto il tempo.

16

C'è ancora un motivo per cui la notifica può restituire: wakeful spurie. Questa è una cosa improbabile ma possibile, perché prevenire wakeups spuri è molto costoso su alcune combinazioni hardware/SO.

Per questo motivo è necessario chiamare wait() in un ciclo e ricontrollare la condizione che si sta aspettando. Durante questo lavoro è facile controllare il timeout allo stesso tempo.

Per i dettagli, raccomando il libro "Concurrency in pratica Java". E usando costrutti di livello superiore che ti fanno tutto ciò che è giusto per te.

+0

+1 Avrò in considerazione quei wakeful spuri –

2

Non c'è modo di dirlo direttamente - cioè, è necessario aggiungere altro codice per determinare ciò. Spesso quando aspetti(), stai aspettando che accada qualcosa che cambi in qualche modo lo stato di un oggetto - ad es. impostando una variabile booleana, forse. Se questo è il caso, allora potresti essere in grado di controllare semplicemente lo stato di quella variabile per vedere se l'evento si è verificato, o sei semplicemente scaduto. Oppure puoi guardare il valore di System.currentTimeMillis() per vedere che il tempo trascorso è maggiore o uguale al periodo di timeout - se lo è, sarebbe un indizio probabilmente scaduto (anche se non è una garanzia assoluta). O se il tempo trascorso è inferiore al periodo di timeout, allora non si è verificato il timeout. Questo aiuta?

+0

Attualmente sto usando currentTimeMillis(), ma mi chiedevo se ci fosse un modo migliore –

+0

@ Hernán Eche Come ho messo nella mia risposta non è una garanzia assoluta. se puoi dirlo, perché vuoi identificare se è scaduto? Possiamo cercare una soluzione. – YoK

+0

sì, so che non è un approccio molto buono, lo uso per un ciclo while (true) {wait (timeout); altri compiti ..; } così può uscire dal ciclo quando l'attesa è stata realmente notificata, ad esempio se wait restituisce booleano, sarebbe qualcosa di simile a quando (true) {if (wait (timeout)) break; altri compiti ..; } comunque lo incapsulerò tutto all'interno di una classe e una bandiera con metodo sincronizzato per aspettare/notificare in parallelo con l'impostazione di questo flag –

3

Non utilizzare System.currentTimeMillis(), utilizzare System.nanoTime().

Il primo misura il tempo assoluto (basato sull'orologio di sistema) e potrebbe avere risultati curiosi se l'ora del sistema viene modificata. Ad esempio: Un'attesa di 5 secondi può avere una durata di un'ora se l'orologio viene spostato all'indietro di un'ora, oppure un'attesa di 10 minuti verrà eseguita dopo 0 secondi se l'orologio viene spostato di fronte.

Il secondo misura il tempo relativo. Funzionerà sempre in una direzione a velocità costante, ma non ha origine. Ciò significa che i valori possono essere utilizzati solo per misurare il tempo relativo, ma non possono e non devono essere utilizzati per determinare una data.