2011-12-23 30 views
9

In caso di un timeout specifico, ho bisogno di uccidere/annullare/interrompere/fallire un thread in esecuzione. Io uso ExecutorService per gestire un pool di thread, attraverso il quale sono in grado di annullare l'attività utilizzando il metodo cancel() di Future che rimuove questo dalla vista ExecutorService, ma il thread stesso continua a funzionare.Interrompe/uccide un thread corrente

Guardandosi intorno online, le persone talk about interrupting threads hanno un ciclo che utilizza il metodo isInterrupted() o sono in attesa su IO che può essere gestito dall'affiorare InterruptedException.

Qual è la pratica generale sull'uccisione dei thread che non esegue il ciclo (o ha altri hook) e non sta aspettando l'I/O? Guardandosi intorno, Thread.stop() sembra fare ciò di cui ho bisogno (uccidendo ciecamente il thread) ma non è consigliabile utilizzarlo.

+1

"uccidere ciecamente il thread" è qualcosa che non si dovrebbe fare, mai. – Viruzzo

+0

Thread.stop() va bene solo per piccoli pezzi di codice in cui è possibile comprendere le conseguenze dell'arresto su ogni linea possibile. Questo tipo di codice è anche semplice per aggiungere linee per controllare il flag interrotto. cioè non è una soluzione ideale nemmeno in teoria. –

risposta

3

Se si utilizza uno ExecutorService, non si dovrebbe fare un pasticcio con i suoi thread: questa nozione è nascosta dietro l'executor che è una nozione di livello superiore rispetto ai thread e quindi non fornisce metodi per gestirli. Ti consiglio vivamente di fermare l'intero esecutore e non provare a fermare uno dei suoi thread.

Si prega di notare che i thread in un ExecutorService sono in loop, il loro ciclo include l'attesa di un task disponibile nella loro coda di attività.

Non v'è alcun mezzo semplice in Java per fermare un filo che non è un loop, che cosa si può fare è:

  • Avere un flag booleano volatile che del thread Runnable assegni da tempo per vedere se deve fermarsi (lo stesso flag che potrebbe essere usato come condizione in un loop di thread).
  • chiamata Thread.interrupt() da provare (best effort, piuttosto pericoloso se non si sa cosa si sta facendo) interrompe una sincronizzazione legati attesa/blocco/Aquire/... il filo è bloccato in.
1

I ti consiglierei personalmente di seguire la rotta di interruzione perché è il modo più pulito e il modo elegante per terminare quel thread.

Consente di definire correttamente il nostro obiettivo. Un thread non è altro che un processo separato che sta per eseguire una serie di attività che gli si assegna. Probabilmente dovrai trovare i punti interrompibili nel tuo codice e fare un controllo interrotto() in questi punti. Ovviamente questi punti avrebbero dovuto raggiungere un finale logico.

Per esempio,

public void run(){ 
     if (Thread.currentThread().interrupted()) { 
      return; 
     } 
     //LogicA start 
     //LogicA end 
     if (Thread.currentThread().interrupted()) { 
      return; 
     } 
     //LogicB start 
     //LogicB end 
     if (Thread.currentThread().interrupted()) { 
      return; 
     } 
     //LogicLong start 
     //Long code here cannot end or exit or kill the thread now. Let it finish 
     //LogicLong ends 
     if (Thread.currentThread().interrupted()) { 
      return; 
     } 
     //LogicD start 
     //LogicD end 
} 
+0

Utilizzare Thread.interrupted() con cautela: ripristina lo stato di interruzione del thread e molte classi dell'API Java lo utilizzano, portando a un'interruzione che non viene notata a livello di Thread. – Guillaume

+0

Non proprio. Dando più contesto qui, il thread istanzia una classe attraverso un'interfaccia e chiama metodi specifici della classe. L'implementazione dei metodi è definita dagli utenti del mio sistema e mi aspetto difetti come loop infiniti. Voglio evitare questo uccidendo i lavori che superano un timeout. – nija

+0

@NiranjanJayakar: In tal caso, probabilmente il controllo dell'interruzione deve essere controllato all'inizio di tale ciclo infinito. – bragboy

1

Se alread hanno un Executorservice allora si hanno ricevuto un Future già. L'unico modo sano e pulito per annullare il lavoro è quindi chiamare future.cancel(boolean mayInterruptIfRunning). L'impostazione mayInterruptIfRunning interromperà i lavori se è attualmente in esecuzione e non fa nulla se il lavoro non è in esecuzione. Quindi devi solo scrivere il lavoro in un modo per onorare l'interruzione controllando di tanto in tanto Thread.interrupted().

Si prega di notare la differenza tra un lavoro e un thread. Si invia un lavoro e pertanto non si dovrebbe utilizzare un thread thread cercando di aggirare lo ExecutorService che potrebbe non essere affatto divertito. Chiamando il numero Future.cancel(true) dai a tutte le parti coinvolte un segnale chiaro su cosa fare.

+0

concordato. Ma voglio un equivalente di una combinazione SIGTERM/SIGKILL alla discussione. Sono scontento di avere lavori infinitamente in esecuzione o difettosi che possono essere costosi per il mio sistema. – nija

Problemi correlati