2010-01-21 13 views
5

Desidero gestire un elenco di oggetti Futures restituiti dal mio TaskExecutor.
Ho qualcosa di simileThread Java - comportamento strano Thread.interrupted() e future.cancel (true)

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 è un compito che implementa Callable < String> e controlli per Thread.interrupted) Stato

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

(Ora il problema è che solo un sottoinsieme di i Thread simultanei restituiscono 'true' quando viene chiamato Thread.interrupted().
L'affermazione in removeFutures() restituisce true per ogni futuro rimosso (Ho verificato anche isDone() ed isCompleted().
Il numero di thread interrotti è casuale. Più di 15 thread in esecuzione a volte 13 sono interrotti, a volte 2 ...
Io davvero non capisco dove sia il problema, se chiamo future.cancel (true) e questo restituisce true ... e poi controllo Thread.interrupted (questo è chiamato solo una volta), mi aspetto questo per tornare vero pure.
Qualsiasi idea di che cosa mi manca?

sono su di generazione Java 1.6.0_02-b05

risposta

2

almeno, si dovrebbe ripristinare l'INTERR uption bandiera per rendere TaskExecutor a conoscenza dell'interruzione filo:

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

grazie per la vostra risposta. qual è il punto di fare questo? Se Thread.interrupted() restituisce true, interrompo il ciclo while e fondamentalmente uccido il thread. Il problema è che a volte Thread.interrupted() restituisce 'false' anche se il relativo future.cancel (true) restituisce true. La linea che hai modificato non può nemmeno essere raggiunta in quel momento. – marts

+0

Quindi il flag di interruzione è probabilmente perso da qualche parte in 'doSomething()' (per lo stesso motivo - qualcosa reimposta il flag e non ripristina in). Cioè, campione nella mia risposta è un principio di base che dovrebbe essere usato per evitare interruzioni perse – axtavt

+0

Se questo è il caso ('evitare interruzioni perse') non potrei semplicemente usare qualcosa come Thread.currentThread(). IsInterrupted() invece di dover ripristinare lo stato di interruzione ogni volta che utilizzo Thread.interrupted(). (A proposito c'è un bug con questo: http://stackoverflow.com/questions/2012259/) Non ho a che fare con lo stato di interruzione in doSomething. – marts

2

Un potenziale problema che gli interrupt sono spesso ingerite. Quindi da qualche parte in profondità nel doSomething() (o anche nel caricamento di classe), un interrupt può essere catturato, per esempio, wait() e quindi scartato dal codice "trascurato". Le interruzioni sono cattive, IMO.

Può valere la pena verificare che tutte le attività siano effettivamente in esecuzione al momento dell'annullamento.

6

Si noti che Thread.interrupted() restituisce lo stato corrente interrotto e quindi lo cancella, quindi tutte le chiamate future restituiranno false. Quello che vuoi è probabilmente Thread.currentThread().isInterrupted().

Inoltre, tenere presente che future.cancel(true) in genere restituisce solo false se l'attività era già stata completata o annullata. Se restituisce true, non è garantito che l'attività verrà effettivamente annullata.

Che cosa succede in doSomething()? È possibile che una RuntimeException sfugga da qualche parte a causa dell'interrupt. Hai un set UncaughtExceptionHandler? In caso contrario, sarà necessario passare uno ThreadFactory allo Executor che imposterà il gestore delle eccezioni e registrerà eventuali eccezioni mancanti.

+0

Sono consapevole di questo. Sto chiamando Thread.interrupted() solo una volta dopo un po '{. Ad ogni modo se ritorna vero mi rompo; e uccidi immediatamente il Thread (e non tocco/controllo l'interruzione da nessun'altra parte). Darei un'occhiata a UncaughtExceptionHandler. grazie mille per la tua risposta (Attenzione a questo bug in Thread.currentThread(). IsInterrupted() http://bugs.sun.com/view_bug.do?bug_id=6772683) – marts

+0

Attualmente, stai usando correttamente Thread.interrupted() modo sicuro. Tuttavia, se non hai bisogno del comportamento fornito da quel metodo, non dovresti usarlo come qualcun altro (o tu stesso) potrebbe refactoring quel metodo tale che Thread.interrupted() viene chiamato in un modo che invalida la gestione degli interrupt . È molto più sicuro usare Thread.currentThread(). IsInterrupted() se puoi. – Kevin

+0

Ciao Kevin. Hai ragione ma a causa del problema con la licenza Java non riesco ad aggiornare la JVM 1.6.0_02-b05 corrente. Sono in esecuzione su un computer con più processori e la mia JVM può essere influenzata dal bug che ho collegato nel commento precedente (qui è un post correlato in stackoverflow http://stackoverflow.com/questions/2012259/). Informazioni sull'eccezione non gestita, se un'uscita RuntimeException posso immaginare che il thread muoia da solo, giusto? qui il mio problema è il contrario ... non si fermano. (o almeno un sottoinsieme viene interrotto) – marts