2010-01-21 14 views
5

Chcę zarządzać listą obiektów Futures zwróconych przez mojego TaskExecutor.
mam coś takiegoWątek Java - dziwne Thread.interrupted() i future.cancel (true) zachowanie

List<Future<String>> list 

void process(ProcessThis processThis) {  
    for (...) { 
     Future<String> future = taskExecutor.submit(processThis); 
     list.add(future) 
    } 
} 


void removeFutures() { 
    for(Future future : list) { 
     assert future.cancel(true); 
} 

ProcessThis jest zadaniem, które realizuje wywoływalnym < string> i kontrole na Thread.interrupted) Status

public String call() { 
     while (true) { 
      if (Thread.interrupted()) { 
       break; 
      } 
      doSomething(); 
     } 
    } 

(Teraz problemem jest to, że tylko podzbiór Współbieżne wątki zwracają "true" po wywołaniu Thread.interrupted().
assert w removeFutures() zwraca wartość true dla każdej przyszłej, która została usunięta (ja sprawdziłem również isDone() i isCompleted()
Liczba wątków, które są przerywane, jest losowa, ponad 15 uruchomionych wątków czasami 13 jest przerywanych, czasami 2 ...
Naprawdę nie rozumiem, gdzie jest problem, jeśli zadzwonię do future.cancel (true) i to zwróci true ... a następnie sprawdzam Thread.interrupted (to jest wywoływane tylko raz), spodziewam się ten powrót prawda, jak również.
żadnego pomysłu na to, co mi brakuje?

Jestem na kompilacji java 1.6.0_02-B05

Odpowiedz

2

przynajmniej, należy przywrócić interr Flaga uption aby taskExecutor świadome zerwanie gwintu:

public String call() { 
    while (true) { 
     if (Thread.interrupted()) { 
      Thread.currentThread().interrupt(); 
      break; 
     } 
     doSomething(); 
    } 
} 
+0

dzięki za odpowiedź. jaki jest sens robienia tego? Jeśli Thread.interrupted() zwróci true, przerywam cykl while i zasadniczo zabijam wątek. Problem polega na tym, że czasami Thread.interrupted() zwraca "false", nawet jeśli powiązana future.cancel (true) zwraca true. Edytowana linia nie może być w tym czasie osiągnięta. – marts

+0

Następnie flaga przerwania jest prawdopodobnie zgubiona gdzieś w 'doSomething()' (z tego samego powodu - coś resetuje flagę i nie przywraca). To znaczy, próbka w mojej odpowiedzi jest podstawową zasadą, której należy używać w celu uniknięcia utraconych przerwań. – axtavt

+0

Jeśli tak jest ("unikaj zagubionych przerwań") nie mogę po prostu użyć czegoś takiego jak Thread.currentThread(). IsInterrupted() zamiast konieczności przywracania stanu przerwania za każdym razem, gdy używam Thread.interrupted(). (BTW jest błąd z tym: http://stackoverflow.com/questions/2012259/) Nie mam do czynienia ze stanem przerwania w doSomething. – marts

2

Potencjalny problem, że przerwania są często połknięciu. Więc gdzieś głęboko w doSomething() (lub nawet w ładowaniu klasy), przerwanie może zostać przechwycone przez, powiedzmy, wait(), a następnie odrzucone przez "nieostrożny" kod. Przerwania są złe, IMO.

Może warto sprawdzić, czy wszystkie zadania są wykonywane w momencie anulowania.

6

Należy pamiętać, że Thread.interrupted() zwraca bieżący stan przerwań , a następnie czyści go, więc wszystkie przyszłe wywołania zwrócą wartość false. To, czego chcesz, to prawdopodobnie Thread.currentThread().isInterrupted().

Pamiętaj też, że zwykle future.cancel(true) zwróci wartość false tylko wtedy, gdy zadanie zostało już zakończone lub anulowane. Jeśli zwróci true, nie ma gwarancji, że zadanie zostanie faktycznie anulowane.

Co się dzieje w doSomething()? Jest możliwe, że wyjątek RuntimeException ucieka gdzieś z powodu przerwania. Czy masz zestaw UncaughtExceptionHandler? Jeśli nie, musisz przekazać ThreadFactory do Executor, która ustawi procedurę obsługi wyjątku i zapisze wszystkie nieodebrane wyjątki.

+0

Jestem tego świadomy. Dzwonię Thread.interrupted() tylko raz po chwili {. W każdym razie, jeśli zwraca true, łamam; i natychmiast zabij Nici (i nie dotykaj/sprawdzaj przerwania nigdzie indziej). Zajrzę do UncaughtExceptionHandler. bardzo dziękuję za odpowiedź. (BTW należy pamiętać o tym błędzie w Thread.currentThread(). IsInterrupted() http://bugs.sun.com/view_bug.do?bug_id=6772683) – marts

+0

Obecnie poprawnie używasz Thread.interrupted() w bezpieczny sposób. Jeśli jednak nie potrzebujesz zachowania zapewnionego przez tę metodę, nie powinieneś używać go tak, jak ktoś inny (lub ty sam) mógłbyś tę metodę wywołać w taki sposób, że Thread.interrupted() jest wywoływana w sposób, który unieważnia obsługę przerwań . Znacznie bezpieczniej jest używać Thread.currentThread(). IsInterrupted(), jeśli możesz. – Kevin

+0

Cześć Kevin. Masz rację, ale z powodu problemu z licencją Java nie mogę zaktualizować bieżącego JVM 1.6.0_02-b05. Pracuję na maszynie wieloprocesorowej, a mój JVM może zostać dotknięty przez błąd, który został połączony w poprzednim komentarzu (tutaj jest powiązany post w stackoverflow http://stackoverflow.com/questions/2012259/). O nieobsługiwanym wyjątku, jeśli wyjątek RuntimeException mogę sobie wyobrazić, że wątek umiera sam, prawda? tutaj mój problem jest odwrotny ... nie zatrzymują się. (lub przynajmniej ich podzbiór jest zatrzymany) – marts