Ś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.
- Wątek nr 1 wywołuje
future.isCancelled()
. Wynikiem jestfalse
, ponieważ zadanie jest nadal w toku. - Wątek nr 2 anuluje zadanie dzwoniąc pod numer
future.cancel()
. - Wątek nr 1 wywołuje
future.isDone()
. Rezultatem jest teraztrue
. - Ocena wyrażenia powyżej wydajności
true
, i jest to niepoprawna odpowiedź.
Jak uniknąć tego problemu?
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?) –
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
Czy zwarcie operatora '&&' nie wystarcza, aby to zapewnić? –