2014-06-23 13 views
6

Śledzę wykonanie zadania za pomocą standardowego obiektu Future. Istnieją następujące ważne stany tego zadania (jak widzę w kodzie guawy z AbstractFuture klasa):Jak sprawdzić, czy Java Future jest kompletna?

  • Running;
  • Completing;
  • Ukończony pomyślnie lub z wyjątkiem;
  • Anulowane;
  • Przerwano.

Future.isDone() powraca true wtedy i tylko wtedy, gdy stan jest zakończone, odwołany lub przerwany. Future.isCancelled() zwraca true wtedy i tylko wtedy, gdy stan jest przerwany lub anulowany.

Ok, ale muszę sprawdzić, czy zadanie jest zakończone. Jest to oczywisty sposób:

boolean isCompleted = future.isDone() && !future.isCancelled(); 

Niestety, ukrywa się tam paskudny błąd współbieżności.

  1. Wątek nr 1 wywołuje future.isCancelled(). Wynikiem jest false, ponieważ zadanie jest nadal w toku.
  2. Wątek nr 2 anuluje zadanie dzwoniąc pod numer future.cancel().
  3. Wątek nr 1 wywołuje future.isDone(). Rezultatem jest teraz true.
  4. Ocena wyrażenia powyżej wydajności true, i jest to niepoprawna odpowiedź.

Jak uniknąć tego problemu?

+1

Nie rozumiem twojego komentarza dotyczącego spekulacyjnego optymalizatora w drugiej odpowiedzi. Możesz wytłumaczyć? W jaki sposób zmienia to ustawienie w '&&'? (Czy to jest nawet to, o czym mówisz?) –

+1

Czy to naprawdę się dzieje? Widzę, że javadoc z 'isDone()' nie gwarantuje 'happen-before' dla' isDone() ', ale zarówno' FutureTask' i Guava 'AbstractTask' są implementowane w taki sposób, który gwarantuje to. – axtavt

+0

Czy zwarcie operatora '&&' nie wystarcza, aby to zapewnić? –

Odpowiedz

2

Możesz spróbować wywołać get(..) z bardzo krótkim czasem oczekiwania. Jeśli zwraca wartość, została zakończona. Jeśli otrzymasz numer TimeoutException, nie był. Jeśli wystąpi jakikolwiek inny z możliwych wyjątków, został anulowany, nieudany lub został przerwany.

+0

Tak, to działa. Ale to raczej niezręczne rozwiązanie, imho –

Powiązane problemy